﻿using FantasyWereld.DataModel;
using FantasyWereld.Code;
using FantasyWereld.Common;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using Windows.ApplicationModel;
using Windows.Data.Xml.Dom;
using Windows.Storage;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using Windows.Data.Json;
using System.Net;

// The data model defined by this file serves as a representative example of a strongly-typed
// model that supports notification when members are added, removed, or modified.  The property
// names chosen coincide with data bindings in the standard item templates.
//
// Applications may use this model as a starting point and build on it, or discard it entirely and
// replace it with something appropriate to their needs.

namespace FantasyWereld.Data
{
    #region DataModel classes

    #region BookInfo
    public class FWBookInfo : FantasyWereld.Common.BindableBase
    {
        private static Uri _baseUri = new Uri("ms-appx:///");

        public FWBookInfo(String appLink, String imagePath, String title)
        {
            this._appLink = appLink;
            if (imagePath != "")
                this._imagePath = imagePath;
            this._title = title;
        }

        private string _appLink = string.Empty;
        public string AppLink
        {
            get { return this._appLink; }
            set { this.SetProperty(ref this._appLink, value); }
        }

        private ImageSource _image = null;
        private String _imagePath = null;
        public ImageSource Image
        {
            get
            {
                if (this._image == null && this._imagePath != null)
                {
                    this._image = new BitmapImage(new Uri(FWBookInfo._baseUri, this._imagePath));
                }
                return this._image;
            }

            set
            {
                this._imagePath = null;
                this.SetProperty(ref this._image, value);
            }
        }

        private string _title = string.Empty;
        public string Title
        {
            get { return this._title; }
            set { this.SetProperty(ref this._title, value); }
        }
    }
    #endregion

    /// <summary>
    /// Base class for <see cref="FWDataItem"/> and <see cref="FWDataGroup"/> that
    /// defines properties common to both.
    /// </summary>
    [Windows.Foundation.Metadata.WebHostHidden]
    public abstract class FWDataCommon : FantasyWereld.Common.BindableBase
    {
        private static Uri _baseUri = new Uri("ms-appx:///");

        public FWDataCommon(String uniqueId, String title, String imagePath, String description, int count)
        {
            this._uniqueId = uniqueId;
            this._title = title;
            this._description = description;
            this._imagePath = imagePath;
            this._count = count;
        }

        private int _count = 0;
        public int Count
        {
            get { return this._count; }
            set { this.SetProperty(ref this._count, value); }
        }

        private string _description = string.Empty;
        public string Description
        {
            get { return this._description; }
            set { this.SetProperty(ref this._description, value); }
        }

        private ImageSource _image = null;
        private String _imagePath = null;
        public ImageSource Image
        {
            get
            {
                if (this._image == null && this._imagePath != null)
                {
                    this._image = new BitmapImage(new Uri(FWDataCommon._baseUri, this._imagePath));
                }
                return this._image;
            }

            set
            {
                this._imagePath = null;
                this.SetProperty(ref this._image, value);
            }
        }
        public string ImageLink
        {
            get { return this._imagePath; }
        }

        private string _title = string.Empty;
        public string Title
        {
            get { return this._title; }
            set { this.SetProperty(ref this._title, value); }
        }

        private string _uniqueId = string.Empty;
        public string UniqueId
        {
            get { return this._uniqueId; }
            set { this.SetProperty(ref this._uniqueId, value); }
        }

        public Uri ImagePath
        {
            get
            {
                return new Uri(FWDataCommon._baseUri, this._imagePath);
            }
        }
        public void SetImage(String path)
        {
            this._image = null;
            this._imagePath = path;
            this.OnPropertyChanged("Image");
        }

        public override string ToString()
        {
            return this.Title;
        }
    }

    /// <summary>
    /// Generic item data model.
    /// </summary>
    public class FWDataItem : FWDataCommon
    {
        private static Uri _baseUri = new Uri("ms-appx:///");

        public FWDataItem()
            : base(String.Empty, String.Empty, String.Empty, String.Empty, 0)
        {
        }

        public FWDataItem(String uniqueId, String title, String imagePath, String description, String content, int count, FWDataGroup group)
            : base(uniqueId, title, imagePath, description, count)
        {
            this._group = group;
        }

        private DateTime _added = DateTime.Now;
        public DateTime Added
        {
            get { return this._added; }
            set { this.SetProperty(ref this._added, value); }
        }

        private string _age = string.Empty;
        public string Age
        {
            get { return this._age; }
            set { this.SetProperty(ref this._age, value); }
        }

        private string _author = string.Empty;
        private string _authorFirstName = string.Empty;
        private string _authorLastName = string.Empty;
        public string Author
        {
            get { return this._author; }
            set
            {
                this.SetProperty(ref this._author, value);
                var x = this._author.Split(',');
                try
                {
                    _authorLastName = x[0].Trim();
                    _authorFirstName = x[1].Trim();
                }
                catch
                {
                    _authorFirstName = _authorLastName;
                }
            }
        }
        public string AuthorFirstName
        {
            get { return this._authorFirstName; }
        }
        public string AuthorLastName
        {
            get { return this._authorLastName; }
        }

        private string _authorLink = string.Empty;
        public string AuthorLink
        {
            get { return this._authorLink; }
            set { this.SetProperty(ref this._authorLink, value); }
        }

        private string _authorContent = string.Empty;
        public string AuthorContent
        {
            get { return this._authorContent; }
            set { this.SetProperty(ref this._authorContent, value); }
        }

        private string _authorCountry = string.Empty;
        public string AuthorCountry
        {
            get { return this._authorCountry; }
            set { this.SetProperty(ref this._authorCountry, value); }
        }

        private string _authorWebsite = string.Empty;
        public string AuthorWebsite
        {
            get { return this._authorWebsite; }
            set { this.SetProperty(ref this._authorWebsite, value); }
        }
        public Uri AuthorWebsiteUri
        {
            get
            {
                if ((AuthorWebsite == null) || (AuthorWebsite == ""))
                    return null;
                else
                    return new Uri(AuthorWebsite);
            }
        }

        private string _authorUniqueId = string.Empty;
        public string AuthorUniqueId
        {
            get { return this._authorUniqueId; }
            set { this.SetProperty(ref this._authorUniqueId, value); }
        }

        private ObservableCollection<FWBookInfo> _authorBooks = new ObservableCollection<FWBookInfo>();
        public ObservableCollection<FWBookInfo> AuthorBooks
        {
            get { return this._authorBooks; }
        }

        private ObservableCollection<FWBookInfo> _authorReviews = new ObservableCollection<FWBookInfo>();
        public ObservableCollection<FWBookInfo> AuthorReviews
        {
            get { return this._authorReviews; }
        }

        private string _books = string.Empty;
        private int _nr_books = 0;
        public string Books
        {
            get { return this._books; }
            set
            {
                this.SetProperty(ref this._books, value);
                var x = _books.Split('|');
                _nr_books = x.Count() / 3;
            }
        }
        public int NrOfBooks
        {
            get { return this._nr_books; }
        }

        private string _content = string.Empty;
        public string Content
        {
            get { return this._content; }
            set { this.SetProperty(ref this._content, value); }
        }

        private string _country = string.Empty;
        public string Country
        {
            get { return this._country; }
            set { this.SetProperty(ref this._country, value); }
        }

        private string _edition = string.Empty;
        public string Edition
        {
            get { return this._edition; }
            set { this.SetProperty(ref this._edition, value); }
        }

        private FWDataGroup _group;
        public FWDataGroup Group
        {
            get { return this._group; }
            set { this.SetProperty(ref this._group, value); }
        }

        private string _isbn = string.Empty;
        public string ISBN
        {
            get { return this._isbn; }
            set { this.SetProperty(ref this._isbn, value); }
        }

        private bool _isupdated = false;
        public bool IsUpdated
        {
            get { return this._isupdated; }
            set { this.SetProperty(ref this._isupdated, value); }
        }

        private string _link = string.Empty;
        public string Link
        {
            get { return this._link; }
            set { this.SetProperty(ref this._link, value); }
        }

        private string _price = string.Empty;
        public string Price
        {
            get { return this._price; }
            set { this.SetProperty(ref this._price, value); }
        }

        private string _publisher = string.Empty;
        public string Publisher
        {
            get { return this._publisher; }
            set { this.SetProperty(ref this._publisher, value); }
        }

        private string _publishdate = string.Empty;
        public string PublishDate
        {
            get { return this._publishdate; }
            set { this.SetProperty(ref this._publishdate, value); }
        }

        private string _quote = string.Empty;
        public string Quote
        {
            get { return this._quote; }
            set { this.SetProperty(ref this._quote, value); }
        }

        private string _reviewer = string.Empty;
        public string Reviewer
        {
            get { return this._reviewer; }
            set { this.SetProperty(ref this._reviewer, value); }
        }

        private ImageSource _stars = null;
        private String _starsPath = null;
        public ImageSource Stars
        {
            get
            {
                if (this._stars == null && this._starsPath != null)
                {
                    this._stars = new BitmapImage(new Uri(FWDataItem._baseUri, this._starsPath));
                }
                return this._stars;
            }

            set
            {
                this._starsPath = null;
                this.SetProperty(ref this._stars, value);
            }
        }
        public string StarsLink
        {
            get { return this._starsPath; }
        }
        public void SetStars(String path)
        {
            this._stars = null;
            this._starsPath = path;
            this.OnPropertyChanged("Stars");
        }

        private bool _showNew = false;
        public bool ShowNew
        {
            get { return this._showNew; }
            set { this.SetProperty(ref this._showNew, value); }
        }

        private bool _showRecent = false;
        public bool ShowRecent
        {
            get { return this._showRecent; }
            set { this.SetProperty(ref this._showRecent, value); }
        }

        private string _subGenre = string.Empty;
        public string SubGenre
        {
            get { return this._subGenre; }
            set { this.SetProperty(ref this._subGenre, value); }
        }

        private string _titleOriginal = string.Empty;
        public string TitleOriginal
        {
            get { return this._titleOriginal; }
            set { this.SetProperty(ref this._titleOriginal, value); }
        }

        private string _translator = string.Empty;
        public string Translator
        {
            get { return this._translator; }
            set { this.SetProperty(ref this._translator, value); }
        }

        private string _website = string.Empty;
        public string Website
        {
            get { return this._website; }
            set { this.SetProperty(ref this._website, value); }
        }
    }

    /// <summary>
    /// Generic group data model.
    /// </summary>
    public class FWDataGroup : FWDataCommon
    {
        public FWDataGroup(String uniqueId, String title, String imagePath, String description, int count)
            : base(uniqueId, title, imagePath, description, count)
        {
            Items.CollectionChanged += ItemsCollectionChanged;
        }

        private void ItemsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            // Provides a subset of the full items collection to bind to from a GroupedItemsPage
            // for two reasons: GridView will not virtualize large items collections, and it
            // improves the user experience when browsing through groups with large numbers of
            // items.
            //
            // A maximum of 12 items are displayed because it results in filled grid columns
            // whether there are 1, 2, 3, 4, or 6 rows displayed

            // Determine Nr of items to display
            int nrItems = Constants.INITIAL_NR_ITEMS;
            if (ApplicationData.Current.RoamingSettings.Values.ContainsKey("NrOfItems"))
                nrItems = Convert.ToInt16(ApplicationData.Current.RoamingSettings.Values["NrOfItems"]);

            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    if (e.NewStartingIndex < nrItems)
                    {
                        TopItems.Insert(e.NewStartingIndex, Items[e.NewStartingIndex]);
                        if (TopItems.Count > nrItems)
                        {
                            TopItems.RemoveAt(nrItems);
                        }
                    }
                    break;
                case NotifyCollectionChangedAction.Move:
                    if (e.OldStartingIndex < nrItems && e.NewStartingIndex < nrItems)
                    {
                        TopItems.Move(e.OldStartingIndex, e.NewStartingIndex);
                    }
                    else if (e.OldStartingIndex < nrItems)
                    {
                        TopItems.RemoveAt(e.OldStartingIndex);
                        TopItems.Add(Items[nrItems - 1]);
                    }
                    else if (e.NewStartingIndex < nrItems)
                    {
                        TopItems.Insert(e.NewStartingIndex, Items[e.NewStartingIndex]);
                        TopItems.RemoveAt(nrItems);
                    }
                    break;
                case NotifyCollectionChangedAction.Remove:
                    if (e.OldStartingIndex < nrItems)
                    {
                        TopItems.RemoveAt(e.OldStartingIndex);
                        if (Items.Count >= nrItems)
                        {
                            TopItems.Add(Items[nrItems - 1]);
                        }
                    }
                    break;
                case NotifyCollectionChangedAction.Replace:
                    if (e.OldStartingIndex < nrItems)
                    {
                        TopItems[e.OldStartingIndex] = Items[e.OldStartingIndex];
                    }
                    break;
                case NotifyCollectionChangedAction.Reset:
                    TopItems.Clear();
                    while (TopItems.Count < Items.Count && TopItems.Count < nrItems)
                    {
                        TopItems.Add(Items[TopItems.Count]);
                    }
                    break;
            }
        }

        private ObservableCollection<FWDataItem> _items = new ObservableCollection<FWDataItem>();
        public ObservableCollection<FWDataItem> Items
        {
            get { return this._items; }
        }

        private ObservableCollection<FWDataItem> _topItem = new ObservableCollection<FWDataItem>();
        public ObservableCollection<FWDataItem> TopItems
        {
            get { return this._topItem; }
        }

        public List<FWDataItem> ItemsSortedOnTitle
        {
            get { return this._items.OrderBy(p => p.Title).ToList(); }
        }

        public List<FWDataItem> ItemsSortedOnFirstName
        {
            get { return this._items.OrderBy(p => p.AuthorFirstName).ToList(); }
        }

        public List<FWDataItem> ItemsSortedOnLastName
        {
            get { return this._items.OrderBy(p => p.AuthorLastName).ToList(); }
        }

        public List<FWDataItem> ItemsSortedOnCountry
        {
            get { return this._items.OrderBy(p => p.Country).ToList(); }
        }
    }
    #endregion

    /// <summary>
    /// Creates a collection of groups and items with hard-coded content.
    /// 
    /// FWDataSource initializes with placeholder data rather than live production
    /// data so that sample data is provided at both design-time and run-time.
    /// </summary>
    public sealed class FWDataSource
    {
        #region methods
        private static Uri _baseUri = new Uri("ms-appx:///");
        private static bool booksReadFromDisk = false;

        private static FWDataSource _FWDataSource = new FWDataSource();
        private static XmlDocument _FWFullReviews = new XmlDocument();
        private static XmlDocument _FWBookDatabase = new XmlDocument();
        private static XmlDocument _FWAuthorDatabase = new XmlDocument();
        private static XmlDocument _FWNews = new XmlDocument();

        public static void UpdateNews(XmlDocument newsList)
        {
            _FWNews = newsList;
        }

        public static XmlDocument GetNews
        {
            get { return _FWNews; }
        }

        public static int NrOfBooks
        {
            get { return _FWBookDatabase.GetElementsByTagName("UniqueId").Count(); }
        }

        public static bool BooksLoaded
        {
            get
            {
                return _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.BOOKFEED_BD_CODE)).Count > 0;
            }
        }

        public static void LoadBooks()
        {
            if (!BooksLoaded)
            {
                try
                {
                    // Read books from disk and fetch images
                    ReadBooksFromDisk(Constants.BOOKFEED_BD_CODE, false);
                }
                catch
                {
                    // On error switch to offline mode
                    ReadBooksFromDisk(Constants.BOOKFEED_BD_CODE, true);
                }
            }
        }

        public static int NrOfReviews
        {
            get
            {
                return FWDataSource.GetAllReviews().Count();
            }
        }

        public static int NrOfInterviews
        {
            get
            {
                return FWDataSource.GetAllItemsPerGroup(Constants.RSSFEED_IV_CODE).Count();
            }
        }

        public static int NrOfArtikelen
        {
            get
            {
                return FWDataSource.GetAllItemsPerGroup(Constants.RSSFEED_AR_CODE).Count();
            }
        }

        public static int NrOfGastblogs
        {
            get
            {
                return FWDataSource.GetAllItemsPerGroup(Constants.RSSFEED_GB_CODE).Count();
            }
        }

        public static int NrOfOverigeRecensies
        {
            get
            {
                return FWDataSource.GetAllItemsPerGroup(Constants.RSSFEED_OR_CODE).Count();
            }
        }

        public static int NrOfSchrijven
        {
            get
            {
                return FWDataSource.GetAllItemsPerGroup(Constants.RSSFEED_SC_CODE).Count();
            }
        }

        public static int NrOfAuthors
        {
            get
            {
                return FWDataSource.GetAllItemsPerGroup(Constants.AUTHORFEED_CODE).Count();
            }
        }

        public static int NrOfStories
        {
            get
            {
                return FWDataSource.GetAllItemsPerGroup(Constants.SHORTSTORYFEED_CODE).Count();
            }
        }

        // Clear memory in order to be able to reload the app with a new value for TypeId
        public static void SetCounters()
        {
            _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_VW_CODE)).Count = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_VW_CODE)).Items.Count();
            _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_YA_CODE)).Count = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_YA_CODE)).Items.Count();
            _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_KB_CODE)).Count = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_KB_CODE)).Items.Count();
            _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_GN_CODE)).Count = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_GN_CODE)).Items.Count();
        }

        public static int NrOfVW
        {
            get
            {
                return _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_VW_CODE)).Items.Count();
            }
        }
        public static int NrOfYA
        {
            get
            {
                return _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_YA_CODE)).Items.Count();
            }
        }
        public static int NrOfKB
        {
            get
            {
                return _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_KB_CODE)).Items.Count();
            }
        }
        public static int NrOfGN
        {
            get
            {
                return _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_GN_CODE)).Items.Count();
            }
        }

        private static List<string> _allKeyWordsList = new List<string>();

        public static string[] AllKeywords
        {
            get { return _allKeyWordsList.OrderBy(q => q).ToArray(); }
        }

        // Clear memory in order to be able to reload the app with a new value for TypeId
        public static void Clear()
        {
            booksReadFromDisk = false;
            _FWDataSource = new FWDataSource();
        }

        // Return number of items in the list
        public static int GetItemCount
        {
            get { return _FWDataSource.AllGroups.SelectMany(group => group.Items).Count(); }
        }

        private ObservableCollection<FWDataGroup> _allGroups = new ObservableCollection<FWDataGroup>();
        public ObservableCollection<FWDataGroup> AllGroups
        {
            get { return this._allGroups; }
        }

        public ObservableCollection<FWDataGroup> ReviewGroups
        {
            get { return this._allGroups; }
        }

        public static IEnumerable<FWDataGroup> GetGroups(string uniqueId)
        {
            if (uniqueId.Equals("ReviewGroups"))
                return _FWDataSource.AllGroups.Take(4);
            else
                return _FWDataSource.AllGroups;
        }

        public static FWDataGroup GetGroup(string uniqueId)
        {
            // Simple linear search is acceptable for small data sets
            var matches = _FWDataSource.AllGroups.Where((group) => group.UniqueId.Equals(uniqueId));
            if (matches.Count() == 1) return matches.First();
            return null;
        }

        public static FWDataItem GetItem(string uniqueId)
        {
            // Simple linear search is acceptable for small data sets
            var matches = _FWDataSource.AllGroups.SelectMany(group => group.Items).Where(item => item.UniqueId.Equals(uniqueId));
            if (matches.Count() == 1) return matches.First();
            if (matches.Count() > 1) return matches.FirstOrDefault();
            return null;
        }

        public static List<FWDataItem> GetAllItems()
        {
            // Simple linear search is acceptable for small data sets
            return _FWDataSource.AllGroups.SelectMany(group => group.Items).ToList();
        }

        public static List<FWDataItem> GetAllReviews()
        {
            // Simple linear search is acceptable for small data sets
            return _FWDataSource.AllGroups.Where(group => group.UniqueId.StartsWith("R_")).SelectMany(group => group.Items).ToList();
        }

        public static List<FWDataItem> GetAllItemsPerGroup(string groupId)
        {
            // Simple linear search is acceptable for small data sets
            return _FWDataSource.AllGroups.Where(group => group.UniqueId.StartsWith(groupId)).SelectMany(group => group.Items).ToList();
        }

        public static List<FWDataItem> GetAllAuthors()
        {
            // Simple linear search is acceptable for small data sets
            return _FWDataSource.AllGroups.Where(group => group.UniqueId == Constants.AUTHORFEED_CODE).SelectMany(group => group.Items).ToList();
        }

        public static List<FWDataItem> GetAllAuthorsSortedOnAuthor()
        {
            // Simple linear search is acceptable for small data sets
            return _FWDataSource.AllGroups.Where(group => group.UniqueId == Constants.AUTHORFEED_CODE).SelectMany(group => group.Items).OrderBy(item => item.Author).ToList();
        }

        public static List<FWDataItem> GetAllAuthorsSortedOnCountry()
        {
            // Simple linear search is acceptable for small data sets
            return _FWDataSource.AllGroups.Where(group => group.UniqueId == Constants.AUTHORFEED_CODE).SelectMany(group => group.Items).OrderBy(item => item.Country).ToList();
        }
        public static FWDataItem GetAuthor(FWDataItem item)
        {
            // Simple linear search is acceptable for small data sets
            var matches = _FWDataSource.AllGroups.Where(group => group.UniqueId == Constants.AUTHORFEED_CODE).SelectMany(group => group.Items).Where(author => author.Author.Equals(item.Author));
            if (matches.Count() == 1) return matches.First();
            if (matches.Count() > 1) return matches.FirstOrDefault();
            return null;
        }

        public static void AddAuthorInfo(FWDataItem item)
        {
            if (item != null)
            {
                var author = FWDataSource.GetAuthor(item);
                if (author != null)
                {
                    item.AuthorUniqueId = author.UniqueId;
                    item.AuthorCountry = author.Country;
                    item.AuthorContent = author.Content;
                    item.AuthorWebsite = author.Website;
                    if ((author.Books != "") && ((item.AuthorBooks.Count == 0) && (item.AuthorReviews.Count == 0)))
                    {
                        string[] split = author.Books.Split('|');
                        int counter = 1;
                        string uniqueId = "";
                        string imagePath = "";
                        string title = "";
                        foreach (string s in split)
                        {
                            switch (counter)
                            {
                                case 1:
                                    uniqueId = s;
                                    break;
                                case 2:
                                    imagePath = s;
                                    break;
                                case 3:
                                    title = s;

                                    FWBookInfo book = new FWBookInfo(uniqueId, imagePath, title);
                                    if (uniqueId.Contains("BD-"))
                                        item.AuthorBooks.Add(book);
                                    else
                                        item.AuthorReviews.Add(book);

                                    counter = 0;

                                    break;
                            }
                            counter++;
                        }
                    }
                }
            }
        }

        public static List<FWDataItem> GetAllBooks()
        {
            // Simple linear search is acceptable for small data sets
            return _FWDataSource.AllGroups.Where(group => group.UniqueId == Constants.BOOKFEED_BD_CODE).SelectMany(group => group.Items).ToList();
        }

        public static List<FWDataItem> GetAllFeedInfoSortedOnAddedDescending()
        {
            // Simple linear search is acceptable for small data sets
            return _FWDataSource.AllGroups.Where(group => group.UniqueId != Constants.BOOKFEED_BD_CODE).Where(group => group.UniqueId != Constants.AUTHORFEED_CODE).SelectMany(group => group.Items).OrderByDescending(item => item.Added).ToList();
        }

        public class GroupInfoList<T> : List<object>
        {
            public object Key { get; set; }

            public new IEnumerator<object> GetEnumerator()
            {
                return (System.Collections.Generic.IEnumerator<object>)base.GetEnumerator();
            }
        }

        public static List<GroupInfoList<object>> GetAuthorsByLetterSortedOnCountry()
        {
            List<GroupInfoList<object>> groups = new List<GroupInfoList<object>>();

            var query = from item in FWDataSource.GetAllAuthors()
                        orderby ((FWDataItem)item).Country
                        group item by ((FWDataItem)item).Country into g
                        select new { GroupName = g.Key, Items = g };
            foreach (var g in query)
            {
                GroupInfoList<object> info = new GroupInfoList<object>();
                info.Key = g.GroupName;
                foreach (var item in g.Items)
                {
                    info.Add(item);
                }
                groups.Add(info);
            }

            return groups;
        }

        public static List<GroupInfoList<object>> GetAuthorsByLetterSortedOnFirstName()
        {
            List<GroupInfoList<object>> groups = new List<GroupInfoList<object>>();

            var query = from item in FWDataSource.GetAllAuthors()
                        orderby ((FWDataItem)item).AuthorFirstName
                        group item by ((FWDataItem)item).AuthorFirstName[0] into g
                        select new { GroupName = g.Key, Items = g };
            foreach (var g in query)
            {
                GroupInfoList<object> info = new GroupInfoList<object>();
                info.Key = g.GroupName;
                foreach (var item in g.Items)
                {
                    info.Add(item);
                }
                groups.Add(info);
            }

            return groups;
        }

        public static List<GroupInfoList<object>> GetAuthorsByLetterSortedOnLastName()
        {
            List<GroupInfoList<object>> groups = new List<GroupInfoList<object>>();

            var query = from item in FWDataSource.GetAllAuthors()
                        orderby ((FWDataItem)item).Author
                        group item by ((FWDataItem)item).Author[0] into g
                        select new { GroupName = g.Key, Items = g };
            foreach (var g in query)
            {
                GroupInfoList<object> info = new GroupInfoList<object>();
                info.Key = g.GroupName;
                foreach (var item in g.Items)
                {
                    info.Add(item);
                }
                groups.Add(info);
            }

            return groups;
        }

        public static List<GroupInfoList<object>> GetBooksByLetter()
        {
            List<GroupInfoList<object>> groups = new List<GroupInfoList<object>>();

            var query = from item in FWDataSource.GetAllBooks()
                        orderby ((FWDataItem)item).Title
                        group item by ((FWDataItem)item).Title[0] into g
                        select new { GroupName = g.Key, Items = g };
            foreach (var g in query)
            {
                GroupInfoList<object> info = new GroupInfoList<object>();
                info.Key = g.GroupName;
                foreach (var item in g.Items)
                {
                    info.Add(item);
                }
                groups.Add(info);
            }

            return groups;
        }

        public static List<FWDataItem> SortAllItemsOnAddedDescending()
        {
            return FWDataSource.GetAllItems().OrderByDescending(item => item.Added).ToList();
        }

        public static List<FWDataItem> SortAllItemsOnAdded()
        {
            return FWDataSource.GetAllItems().OrderBy(item => item.Added).ToList();
        }

        public static List<FWDataItem> SortAllItemsOnAuthor()
        {
            return FWDataSource.GetAllItems().OrderBy(item => item.Author).ToList();
        }

        public static List<FWDataItem> SortAllItemsOnTitle()
        {
            return FWDataSource.GetAllItems().OrderBy(item => item.Title).ToList();
        }

        public static List<FWDataItem> SortAllItemsOnTitleDescending()
        {
            return FWDataSource.GetAllItems().OrderByDescending(item => item.Title).ToList();
        }

        public static List<FWDataItem> SortAllItemsOnPublishDate()
        {
            return FWDataSource.GetAllItems().OrderBy(item => item.PublishDate).ToList();
        }
        #endregion

        #region Main entry point
        /// <summary>
        /// Load data asynchronously from the app data files into appropriate XML documents
        /// </summary>
        /// <returns></returns>
        public static async Task LoadDataAsync()
        {
            // Setup review XML File
            await SetupDataFile(Constants.XML_FILE_DIR + "\\" + Constants.XML_REVIEWS_FILE_NAME, Constants.XML_REVIEWS_FILE_NAME);
            // Read reviews from XML File
            _FWFullReviews = await Utility.ReadXMLDocumentFromFileAsync(Constants.XML_REVIEWS_FILE_NAME);

            // Setup books database XML File
            await SetupDataFile(Constants.XML_FILE_DIR + "\\" + Constants.XML_BOOKS_FILE_NAME, Constants.XML_BOOKS_FILE_NAME);
            // Read books database from XML File
            _FWBookDatabase = await Utility.ReadXMLDocumentFromFileAsync(Constants.XML_BOOKS_FILE_NAME);

            // Setup authors database XML File
            await SetupDataFile(Constants.XML_FILE_DIR + "\\" + Constants.XML_AUTHORS_FILE_NAME, Constants.XML_AUTHORS_FILE_NAME);
            // Read books database from XML File
            _FWAuthorDatabase = await Utility.ReadXMLDocumentFromFileAsync(Constants.XML_AUTHORS_FILE_NAME);

            // Setup suggestions File
            await SetupDataFile(Constants.XML_FILE_DIR + "\\" + Constants.SUGGESTION_FILE_NAME, Constants.SUGGESTION_FILE_NAME);
            // Read suggestions from suggestions File
            await ReadSuggestionsFromFileAsync();

            // Add groups to datasource
            AddGroupToDataSource(Constants.RSSFEED_VW_CODE, Constants.RSSFEED_VW_TITLE, "", _baseUri + Constants.DEFAULT_IMAGE_PATH + Constants.RSSFEED_VW_CODE + Constants.DEFAULT_IMAGE_EXTENTION);
            AddGroupToDataSource(Constants.RSSFEED_YA_CODE, Constants.RSSFEED_YA_TITLE, "", _baseUri + Constants.DEFAULT_IMAGE_PATH + Constants.RSSFEED_YA_CODE + Constants.DEFAULT_IMAGE_EXTENTION);
            AddGroupToDataSource(Constants.RSSFEED_KB_CODE, Constants.RSSFEED_KB_TITLE, "", _baseUri + Constants.DEFAULT_IMAGE_PATH + Constants.RSSFEED_KB_CODE + Constants.DEFAULT_IMAGE_EXTENTION);
            AddGroupToDataSource(Constants.RSSFEED_GN_CODE, Constants.RSSFEED_GN_TITLE, "", _baseUri + Constants.DEFAULT_IMAGE_PATH + Constants.RSSFEED_GN_CODE + Constants.DEFAULT_IMAGE_EXTENTION);

            AddGroupToDataSource(Constants.BOOKFEED_BD_CODE, Constants.BOOKFEED_TITLE, Constants.BOOKFEED_DESCRIPTION, Constants.BOOKFEED_BD_IMAGE);
            AddGroupToDataSource(Constants.AUTHORFEED_CODE, Constants.AUTHORFEED_TITLE, Constants.AUTHORFEED_DESCRIPTION, Constants.AUTHORFEED_IMAGE);

            AddGroupToDataSource(Constants.RSSFEED_AR_CODE, Constants.RSSFEED_AR_TITLE, "", Constants.RSSFEED_AR_IMAGE);
            AddGroupToDataSource(Constants.RSSFEED_GB_CODE, Constants.RSSFEED_GB_TITLE, "", Constants.RSSFEED_GB_IMAGE);
            AddGroupToDataSource(Constants.RSSFEED_IV_CODE, Constants.RSSFEED_IV_TITLE, "", Constants.RSSFEED_IV_IMAGE);
            AddGroupToDataSource(Constants.RSSFEED_SC_CODE, Constants.RSSFEED_SC_TITLE, "", Constants.RSSFEED_SC_IMAGE);
            AddGroupToDataSource(Constants.RSSFEED_OR_CODE, Constants.RSSFEED_OR_TITLE, "", Constants.RSSFEED_OR_IMAGE);

            AddGroupToDataSource(Constants.SHORTSTORYFEED_CODE, Constants.SHORTSTORYFEED_TITLE, "", Constants.SHORTSTORYFEED_IMAGE);
        }
        #endregion

        #region AddGroupToDataSource
        private static void AddGroupToDataSource(string groupId, string title, string description, string imagePath)
        {
            // Define new FWDataGroup
            FWDataGroup FWObjectGroup = new FWDataGroup(groupId, title, imagePath, "", 0);

            // Only add record to list of groups when it is the first one
            if (_FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(groupId)) == null)
                _FWDataSource.AllGroups.Add(FWObjectGroup);
        }
        #endregion

        #region LoadRemoteDataAsync
        public static async Task LoadRemoteDataAsync()
        {
            bool newReviewsFound = false;
            bool newNewsFound = false;
            bool newStoriesFound = false;

            try
            {
                // Retrieve RSS feed information from Fantasy Wereld webserver
                if (await ProcessFeedAsync(Constants.RSSFEED_VW, Constants.RSSFEED_VW_CODE))
                    newReviewsFound = true;
                if (await ProcessFeedAsync(Constants.RSSFEED_YA, Constants.RSSFEED_YA_CODE))
                    newReviewsFound = true;
                if (await ProcessFeedAsync(Constants.RSSFEED_KB, Constants.RSSFEED_KB_CODE))
                    newReviewsFound = true;
                if (await ProcessFeedAsync(Constants.RSSFEED_GN, Constants.RSSFEED_GN_CODE))
                    newReviewsFound = true;

                // Retrieve additional datafeeds first
                if (await ProcessBasicFeedAsync(Constants.RSSFEED_SC, Constants.RSSFEED_SC_CODE))
                    newNewsFound = true;
                if (await ProcessBasicFeedAsync(Constants.RSSFEED_IV, Constants.RSSFEED_IV_CODE))
                    newNewsFound = true;
                if (await ProcessBasicFeedAsync(Constants.RSSFEED_GB, Constants.RSSFEED_GB_CODE))
                    newNewsFound = true;
                if (await ProcessBasicFeedAsync(Constants.RSSFEED_OR, Constants.RSSFEED_OR_CODE))
                    newNewsFound = true;
                if (await ProcessDoubleFeedAsync(Constants.RSSFEED_AG, Constants.RSSFEED_FA, Constants.RSSFEED_AR_CODE))
                    newNewsFound = true;
                if (await ProcessShortStoriesAsync(Constants.SHORTSTORYFEED, Constants.SHORTSTORYFEED_CODE))
                    newStoriesFound = true;

                if ((newReviewsFound) || (newNewsFound) || (newStoriesFound))
                {
                    await WriteItemsToXMLAsync(Constants.XML_REVIEWS_FILE_NAME, FWDataSource.GetAllFeedInfoSortedOnAddedDescending());
                    await WriteSuggestionsToFileAsync();

                    if (newReviewsFound)
                        Utility.SendNotification(Constants.MESSAGE_NOTIFICATION_HEADER, Constants.MESSAGE_NOTIFICATION_NEW_REVIEWS, Constants.NOTIFICATION_REVIEWS);
                    if (newStoriesFound)
                        Utility.SendNotification(Constants.MESSAGE_NOTIFICATION_HEADER, Constants.MESSAGE_NOTIFICATION_NEW_STORY, Constants.NOTIFICATION_STORIES);
                    if (newNewsFound)
                        Utility.SendNotification(Constants.MESSAGE_NOTIFICATION_HEADER, Constants.MESSAGE_NOTIFICATION_NEW_NEWS, 0);
                }

                FWDataSource.SetCounters();

                // Generate the standard FantasyWereld Tile
                await Utility.GenerateFantasyWereldTile();
            }
            catch
            {
                // On error switch to offline mode
                ProcessCachedReviews();
            }
        }
        #endregion

        #region Handle Search

        #region ProcessSuggestions
        private static void ProcessSuggestions(FWDataItem item)
        {
            // Add suggestions to list
            AddKeywordsToSuggestionList(item.Age);
            AddKeywordsToSuggestionList(item.Author);
            AddKeywordsToSuggestionList(item.Country);
            AddKeywordsToSuggestionList(item.Description);
            AddKeywordsToSuggestionList(item.Edition);
            AddKeywordsToSuggestionList(item.ISBN);
            AddKeywordsToSuggestionList(item.Publisher);
            AddKeywordsToSuggestionList(item.PublishDate);
            AddKeywordsToSuggestionList(item.Quote);
            AddKeywordsToSuggestionList(item.Reviewer);
            AddKeywordsToSuggestionList(item.SubGenre);
            AddKeywordsToSuggestionList(item.Title);
            AddKeywordsToSuggestionList(item.TitleOriginal);
            AddKeywordsToSuggestionList(item.Translator);
        }
        #endregion

        #region WriteSuggestionsToFileAsync
        public static async Task WriteSuggestionsToFileAsync()
        {
            bool saveSuggestionsFileHasFailed = false;

            StringBuilder outputString = new StringBuilder();

            foreach (string item in AllKeywords)
                outputString.Append(item + "\r\n");

            // Determine source folder location
            StorageFolder sourceFolder = await Package.Current.InstalledLocation.GetFolderAsync(Constants.XML_FILE_DIR);
            // Determine destination folder location
            StorageFolder destinationFolder = ApplicationData.Current.LocalFolder;

            try
            {
                // Create new destination filename
                StorageFile filename = await destinationFolder.CreateFileAsync(Constants.SUGGESTION_FILE_NAME, CreationCollisionOption.ReplaceExisting);

                await FileIO.WriteTextAsync(filename, outputString.ToString());
            }
            catch
            {
                saveSuggestionsFileHasFailed = true;
            }

            if (saveSuggestionsFileHasFailed)
            {
                // Create new source filename
                StorageFile sourceFilename = await sourceFolder.GetFileAsync(Constants.SUGGESTION_FILE_NAME);
                // Copy this file to destination location
                await sourceFilename.CopyAsync(destinationFolder, Constants.SUGGESTION_FILE_NAME, NameCollisionOption.ReplaceExisting);
            }
        }
        #endregion

        #region ReadSuggestionsFromFileAsync
        public static async Task ReadSuggestionsFromFileAsync()
        {
            try
            {
                // Determine source folder location
                StorageFolder sourceFolder = ApplicationData.Current.LocalFolder;
                // Determine source filename
                StorageFile sourceFilename = await sourceFolder.GetFileAsync(Constants.SUGGESTION_FILE_NAME);

                // Create Stream
                var stream = await sourceFilename.OpenReadAsync();
                // Create StreamReader
                var streamReader = new StreamReader(stream.AsStream());

                // Read contents of file
                var contents = await streamReader.ReadToEndAsync();

                // Clear allKeywordsList
                _allKeyWordsList.Clear();

                string[] stringSeparators = new string[] { "\r\n" };

                String[] keywords = contents.Split(stringSeparators, StringSplitOptions.RemoveEmptyEntries);
                
                foreach (string x in keywords)
                    if (x.Length > 5)
                    {
                        _allKeyWordsList.Add(x);
                    }

                streamReader.Dispose();
                stream.Dispose();
            }
            catch
            {
            }
        }
        #endregion

        #region AddKeywordsToSuggestionList
        /// <summary>
        /// Add keywords to Suggestion List
        /// </summary>
        private static void AddKeywordsToSuggestionList(string keywordsString)
        {
            keywordsString = Utility.CleanupText(Utility.CleanupHTML(Utility.ReplaceSpecialCodes(keywordsString)));
            keywordsString = keywordsString
                .Replace(":", "")
                .Replace("(", "")
                .Replace(")", "")
                .Replace("\n", "")
                .Replace("?", "")
                .Replace("!", "")
                .Replace(";", "")
                .Replace("&", "")
                .Replace("…", "")
                .Replace("+", "")
                .Replace("*", "")
                .Replace(".", "")
                .Replace(" ", " ") // Unknown character will be replaced by a space
                .Replace(",", "");
            String[] keywords = keywordsString.Split(' ');

            foreach (string x in keywords)
            {
                string resultString = x;
                if (resultString.EndsWith("’"))
                    resultString = resultString.Substring(0, resultString.Length - 1);
                if (resultString.StartsWith("‘"))
                    resultString = resultString.Substring(1, resultString.Length - 1);
                if (resultString.EndsWith("”"))
                    resultString = resultString.Substring(0, resultString.Length - 1);
                if (resultString.StartsWith("“"))
                    resultString = resultString.Substring(1, resultString.Length - 1);

                if ((resultString.Length > 4) || (resultString.Contains("+")))
                {
                    if (!_allKeyWordsList.Exists(p => p == resultString.Trim().ToLower()))
                    {
                        _allKeyWordsList.Add(resultString.Trim().ToLower());
                    }
                }
            }
        }
        #endregion

        #region UpdateKeywordsAsync
        public static async Task UpdateKeywordsAsync()
        {
            // Clear all keywords
            _allKeyWordsList.Clear();

            List<FWDataItem> itemsToProcess = new List<FWDataItem>();

            XmlElement root = _FWFullReviews.DocumentElement;
            XmlNodeList nodes = root.SelectNodes("item");
            foreach (var item in nodes)
            {
                FWDataItem FWItem = new FWDataItem();

                FWItem.Added = Convert.ToDateTime(item.ChildNodes[0].InnerText);
                FWItem.Age = item.ChildNodes[1].InnerText;
                FWItem.Author = item.ChildNodes[2].InnerText;
                FWItem.AuthorLink = item.ChildNodes[3].InnerText;
                FWItem.Content = item.ChildNodes[4].InnerText;
                FWItem.Description = item.ChildNodes[5].InnerText;
                FWItem.Edition = item.ChildNodes[6].InnerText;
                FWItem.Group = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(item.ChildNodes[7].InnerText));
                FWItem.SetImage(item.ChildNodes[8].InnerText);
                FWItem.ISBN = item.ChildNodes[9].InnerText;
                FWItem.Link = item.ChildNodes[10].InnerText;
                FWItem.Price = item.ChildNodes[11].InnerText;
                FWItem.PublishDate = item.ChildNodes[12].InnerText;
                FWItem.Publisher = item.ChildNodes[13].InnerText;
                FWItem.Reviewer = item.ChildNodes[14].InnerText;
                FWItem.SetStars(item.ChildNodes[15].InnerText);
                FWItem.SubGenre = item.ChildNodes[16].InnerText;
                FWItem.Title = Utility.CleanupText(Utility.ReplaceSpecialCodes(item.ChildNodes[17].InnerText));
                FWItem.TitleOriginal = Utility.CleanupText(Utility.ReplaceSpecialCodes(item.ChildNodes[18].InnerText));
                FWItem.UniqueId = item.ChildNodes[19].InnerText;
                FWItem.Quote = item.ChildNodes[20].InnerText;
                FWItem.Translator = item.ChildNodes[21].InnerText;
                FWItem.Website = item.ChildNodes[22].InnerText;
                FWItem.Country = item.ChildNodes[23].InnerText;
                FWItem.Books = item.ChildNodes[24].InnerText;

                // Add new record to search suggestion list
                ProcessSuggestions(FWItem);
            }

            await WriteSuggestionsToFileAsync();
        }
        #endregion


        #endregion

        #region Handle file manipulation

        #region DeleteFile
        public static async Task<bool> DeleteFile(string dstFileName)
        {
            try
            {
                // Determine data folder location
                StorageFolder dataFolder = ApplicationData.Current.LocalFolder;
                bool completedXMLfileExists = await CheckFile(dstFileName, dataFolder);

                if (completedXMLfileExists)
                {
                    // Copy master file to data folder
                    StorageFile srcFile = await dataFolder.GetFileAsync(dstFileName);
                    await srcFile.DeleteAsync();
                }
                return true;
            }
            catch
            {
                return false;
            }
        }
        #endregion

        #region CheckFile
        public static async Task<bool> CheckFile(string filePath, StorageFolder fileFolder)
        {
            try
            {
                StorageFile file = await fileFolder.GetFileAsync(filePath);
                return true;
            }
            catch (System.IO.FileNotFoundException)
            {
                return false;
            }
        }
        #endregion

        #region SetupDataFile
        public static async Task SetupDataFile(string srcFileName, string dstFileName)
        {
            try
            {
                // Determine application folder location
                StorageFolder installedLocation = Package.Current.InstalledLocation;
                bool masterXMLfileExists = await CheckFile(srcFileName, installedLocation);

                // Determine data folder location
                StorageFolder dataFolder = ApplicationData.Current.LocalFolder;
                bool completedXMLfileExists = await CheckFile(dstFileName, dataFolder);

                if (!completedXMLfileExists && masterXMLfileExists)
                {
                    // Copy master file to data folder
                    StorageFile srcFile = await installedLocation.GetFileAsync(srcFileName);
                    await srcFile.CopyAsync(dataFolder);
                }
            }
            catch
            {
            }
        }
        #endregion

        #endregion

        #region Handle Review RSS feeds

        #region ProcessFeedAsync
        /// <summary>
        /// Process RSS Feed
        /// </summary>
        /// <param name="feedName"></param>
        /// <param name="groupId"></param>
        /// <returns></returns>
        private static async Task<bool> ProcessFeedAsync(string feedName, string groupId)
        {
            bool newItemsOnWebsite = false;

            try
            {
                bool firstItem = true;

                var myFeed = await Utility.GetRSSFeedAsync(feedName);

                foreach (var channel in myFeed)
                {
                    foreach (var item in channel.Items)
                    {
                        FWDataItem FWItem = new FWDataItem();

                        FWItem.Title = Utility.CleanupText(Utility.ReplaceSpecialCodes(item.Title));

                        int startIndex = item.Description.IndexOf(Constants.FIND_IMG_TAG_START);
                        int endIndex = item.Description.IndexOf(Constants.FIND_IMG_TAG_END1) + Constants.FIND_IMG_TAG_END1.Length;
                        if ((startIndex > 0) && (endIndex > Constants.FIND_IMG_TAG_END1.Length) && (startIndex < endIndex))
                        {
                            // Image found in description
                            FWItem.SetImage(item.Description.Substring(startIndex, endIndex - startIndex));

                            int end2Index = item.Description.IndexOf(Constants.FIND_IMG_TAG_END2) + 1;
                            string content = Utility.StripHTMLTags(item.Description.Substring(end2Index, item.Description.Length - end2Index));

                            FWItem.Description = Utility.CleanupText(Utility.ReplaceSpecialCodes(content));
                        }
                        else
                        {
                            // Default image selected
                            FWItem.SetImage(_baseUri + Constants.DEFAULT_IMAGE_PATH + groupId + Constants.DEFAULT_IMAGE_EXTENTION);
                            FWItem.Description = Utility.CleanupText(Utility.StripHTMLTags(Utility.ReplaceSpecialCodes(item.Description)));
                        }

                        FWItem.Link = item.Link;

                        // Determine UniqueId
                        FWItem.UniqueId = GenerateUniqueIdForReview(FWItem.Link);

                        // Determine Group
                        FWItem.Group = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(groupId));

                        // Search on UniqueId
                        var nodeList = _FWFullReviews.GetElementsByTagName("UniqueId");
                        XmlElement node = null;

                        if (nodeList.Count > 0)
                            // Find the node with this id from the review file
                            node = FindNode(nodeList, FWItem.UniqueId);

                        if (node != null)
                        {
                            FWItem.Added = Convert.ToDateTime(node.ParentNode.ChildNodes[0].InnerText);
                            FWItem.Age = node.ParentNode.ChildNodes[1].InnerText;
                            FWItem.Author = node.ParentNode.ChildNodes[2].InnerText;
                            FWItem.AuthorLink = node.ParentNode.ChildNodes[3].InnerText;
                            FWItem.Content = node.ParentNode.ChildNodes[4].InnerText;
                            FWItem.Edition = node.ParentNode.ChildNodes[6].InnerText;
                            FWItem.ISBN = node.ParentNode.ChildNodes[9].InnerText;
                            FWItem.Price = node.ParentNode.ChildNodes[11].InnerText;
                            FWItem.PublishDate = node.ParentNode.ChildNodes[12].InnerText;
                            FWItem.Publisher = node.ParentNode.ChildNodes[13].InnerText;
                            FWItem.Reviewer = node.ParentNode.ChildNodes[14].InnerText;
                            FWItem.SetStars(node.ParentNode.ChildNodes[15].InnerText);
                            FWItem.SubGenre = node.ParentNode.ChildNodes[16].InnerText;
                            FWItem.TitleOriginal = node.ParentNode.ChildNodes[18].InnerText;

                            if (firstItem)
                            {
                                Utility.GenerateTile(FWItem);
                                firstItem = false;
                            }
                        }
                        else
                        {
                            // Go to website and fetch full review content 
                            await FetchReviewInfoFromSiteAsync(FWItem);

                            // Add new record to search suggestion list
                            ProcessSuggestions(FWItem);

                            // New item, so set Show New to true
                            FWItem.ShowNew = true;

                            Utility.GenerateTile(FWItem);

                            newItemsOnWebsite = true;
                        }
                        // Show Recent image if (and only if) the item was added more recent than two weeks ago
                        FWItem.ShowRecent = FWItem.Added.AddDays(Constants.NR_RECENT_DAYS) > DateTime.Now;

                        // All fields have been processed

                        if (FWItem.Group.Items.FirstOrDefault(m => m.UniqueId.Equals(FWItem.UniqueId)) == null)
                            // Item does not exist yet
                            // select the group and add this item to the items in this group
                            _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(FWItem.Group.UniqueId)).Items.Insert(0, FWItem);
                    }
                }
            }
            catch { }

            return newItemsOnWebsite;
        }
        #endregion

        #region getChannelQuery
        private static IEnumerable<RSSChannel> getChannelQuery(XDocument xdoc)
        {
            return from channels in xdoc.Descendants("channel")
                   select new RSSChannel
                   {
                       Title = channels.Element("title") != null ? channels.Element("title").Value : "",
                       Link = channels.Element("link") != null ? channels.Element("link").Value : "",
                       Description = channels.Element("description") != null ? channels.Element("description").Value : "",
                       Items = from items in channels.Descendants("item")
                               select new RSSItem
                               {
                                   Title = items.Element("title") != null ? items.Element("title").Value : "",
                                   Link = items.Element("link") != null ? items.Element("link").Value : "",
                                   Description = items.Element("description") != null ? items.Element("description").Value : "",
                                   Guid = (items.Element("guid") != null ? items.Element("guid").Value : "")
                               }
                   };
        }
        #endregion

        #region FindNode
        private static XmlElement FindNode(XmlNodeList list, string nodeName)
        {
            if (list.Count > 0)
                foreach (XmlElement node in list)
                    if (node.InnerText.Equals(nodeName)) return node;
            return null;
        }
        #endregion

        #region WriteItemsToXMLAsync
        public static async Task WriteItemsToXMLAsync(string fileNameToUse, List<FWDataItem> itemsToProcess)
        {
            switch (fileNameToUse)
            {
                case Constants.XML_AUTHORS_FILE_NAME:
                    itemsToProcess.Sort((p1, p2) => p1.Author.CompareTo(p2.Author));
                    break;
                case Constants.XML_REVIEWS_FILE_NAME:
                    itemsToProcess.OrderByDescending(item => item.Added);
                    break;
                default:
                    itemsToProcess.OrderBy(item => item.Title);
                    break;
            }

            if (itemsToProcess.Count > 0)
            {
                bool saveXMLFileHasFailed = false;

                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.LoadXml(Constants.XML_BASE_FILE);

                foreach (FWDataItem item in itemsToProcess)
                {
                    XmlElement newelem = xmlDoc.CreateElement("item");
                    xmlDoc.DocumentElement.AppendChild(newelem);

                    // 0
                    // Added
                    XmlElement appendedElementAdded = xmlDoc.CreateElement("Added");
                    XmlText xmlTextAdded = xmlDoc.CreateTextNode(item.Added.ToString());
                    appendedElementAdded.AppendChild(xmlTextAdded);
                    newelem.AppendChild(appendedElementAdded);
                    xmlDoc.DocumentElement.AppendChild(newelem);

                    // 1
                    // Age
                    XmlElement appendedElementAge = xmlDoc.CreateElement("Age");
                    XmlText xmlTextAge = xmlDoc.CreateTextNode(item.Age);
                    appendedElementAge.AppendChild(xmlTextAge);
                    newelem.AppendChild(appendedElementAge);
                    xmlDoc.DocumentElement.AppendChild(newelem);

                    // 2
                    // Author
                    XmlElement appendedElementAuthor = xmlDoc.CreateElement("Author");
                    XmlText xmlTextAuthor = xmlDoc.CreateTextNode(item.Author);
                    appendedElementAuthor.AppendChild(xmlTextAuthor);
                    newelem.AppendChild(appendedElementAuthor);
                    xmlDoc.DocumentElement.AppendChild(newelem);

                    // 3
                    // AuthorLink
                    XmlElement appendedElementAuthorLink = xmlDoc.CreateElement("AuthorLink");
                    XmlText xmlTextAuthorLink = xmlDoc.CreateTextNode(item.AuthorLink);
                    appendedElementAuthorLink.AppendChild(xmlTextAuthorLink);
                    newelem.AppendChild(appendedElementAuthorLink);
                    xmlDoc.DocumentElement.AppendChild(newelem);

                    // 4
                    // Content
                    XmlElement appendedElementContent = xmlDoc.CreateElement("Content");
                    XmlText xmlTextContent = xmlDoc.CreateTextNode(item.Content);
                    appendedElementContent.AppendChild(xmlTextContent);
                    newelem.AppendChild(appendedElementContent);
                    xmlDoc.DocumentElement.AppendChild(newelem);

                    // 5
                    // Description
                    XmlElement appendedElementDescription = xmlDoc.CreateElement("Description");
                    XmlText xmlTextDescription = xmlDoc.CreateTextNode(item.Description);
                    appendedElementDescription.AppendChild(xmlTextDescription);
                    newelem.AppendChild(appendedElementDescription);
                    xmlDoc.DocumentElement.AppendChild(newelem);

                    // 6
                    // Edition
                    XmlElement appendedElementEdition = xmlDoc.CreateElement("Edition");
                    XmlText xmlTextEdition = xmlDoc.CreateTextNode(item.Edition);
                    appendedElementEdition.AppendChild(xmlTextEdition);
                    newelem.AppendChild(appendedElementEdition);
                    xmlDoc.DocumentElement.AppendChild(newelem);

                    // 7
                    // Group
                    XmlElement appendedElementGroup = xmlDoc.CreateElement("Group");
                    XmlText xmlTextGroup = xmlDoc.CreateTextNode(item.Group.UniqueId);
                    appendedElementGroup.AppendChild(xmlTextGroup);
                    newelem.AppendChild(appendedElementGroup);
                    xmlDoc.DocumentElement.AppendChild(newelem);

                    // 8
                    // ImageLink
                    XmlElement appendedElementImageLink = xmlDoc.CreateElement("ImageLink");
                    XmlText xmlTextImageLink = xmlDoc.CreateTextNode(item.ImageLink);
                    appendedElementImageLink.AppendChild(xmlTextImageLink);
                    newelem.AppendChild(appendedElementImageLink);
                    xmlDoc.DocumentElement.AppendChild(newelem);

                    // 9
                    // ISBN
                    XmlElement appendedElementISBN = xmlDoc.CreateElement("ISBN");
                    XmlText xmlTextISBN = xmlDoc.CreateTextNode(item.ISBN);
                    appendedElementISBN.AppendChild(xmlTextISBN);
                    newelem.AppendChild(appendedElementISBN);
                    xmlDoc.DocumentElement.AppendChild(newelem);

                    // 10
                    // Link
                    XmlElement appendedElementLink = xmlDoc.CreateElement("Link");
                    XmlText xmlTextLink = xmlDoc.CreateTextNode(item.Link);
                    appendedElementLink.AppendChild(xmlTextLink);
                    newelem.AppendChild(appendedElementLink);
                    xmlDoc.DocumentElement.AppendChild(newelem);

                    // 11
                    // Price
                    XmlElement appendedElementPrice = xmlDoc.CreateElement("Price");
                    XmlText xmlTextPrice = xmlDoc.CreateTextNode(item.Price);
                    appendedElementPrice.AppendChild(xmlTextPrice);
                    newelem.AppendChild(appendedElementPrice);
                    xmlDoc.DocumentElement.AppendChild(newelem);

                    // 12
                    // PublishDate
                    XmlElement appendedElementPublishDate = xmlDoc.CreateElement("PublishDate");
                    XmlText xmlTextTPublishDate = xmlDoc.CreateTextNode(item.PublishDate);
                    appendedElementPublishDate.AppendChild(xmlTextTPublishDate);
                    newelem.AppendChild(appendedElementPublishDate);
                    xmlDoc.DocumentElement.AppendChild(newelem);

                    // 13
                    // Publisher
                    XmlElement appendedElementPublisher = xmlDoc.CreateElement("Publisher");
                    XmlText xmlTextPublisher = xmlDoc.CreateTextNode(item.Publisher);
                    appendedElementPublisher.AppendChild(xmlTextPublisher);
                    newelem.AppendChild(appendedElementPublisher);
                    xmlDoc.DocumentElement.AppendChild(newelem);

                    // 14
                    // Reviewer
                    XmlElement appendedElementReviewer = xmlDoc.CreateElement("Reviewer");
                    XmlText xmlTextReviewer = xmlDoc.CreateTextNode(item.Reviewer);
                    appendedElementReviewer.AppendChild(xmlTextReviewer);
                    newelem.AppendChild(appendedElementReviewer);
                    xmlDoc.DocumentElement.AppendChild(newelem);

                    // 15
                    // Stars
                    if (item.StarsLink == null)
                    {
                        XmlElement appendedElementStars = xmlDoc.CreateElement("Stars");
                        XmlText xmlTextStars = xmlDoc.CreateTextNode("");
                        appendedElementStars.AppendChild(xmlTextStars);
                        newelem.AppendChild(appendedElementStars);
                        xmlDoc.DocumentElement.AppendChild(newelem);
                    }
                    else
                    {
                        XmlElement appendedElementStars = xmlDoc.CreateElement("Stars");
                        XmlText xmlTextStars = xmlDoc.CreateTextNode(item.StarsLink);
                        appendedElementStars.AppendChild(xmlTextStars);
                        newelem.AppendChild(appendedElementStars);
                        xmlDoc.DocumentElement.AppendChild(newelem);
                    }

                    // 16
                    // SubGenre
                    XmlElement appendedElementSubGenre = xmlDoc.CreateElement("SubGenre");
                    XmlText xmlTextSubGenre = xmlDoc.CreateTextNode(item.SubGenre);
                    appendedElementSubGenre.AppendChild(xmlTextSubGenre);
                    newelem.AppendChild(appendedElementSubGenre);
                    xmlDoc.DocumentElement.AppendChild(newelem);

                    // 17
                    // Title
                    XmlElement appendedElementTitle = xmlDoc.CreateElement("Title");
                    XmlText xmlTextTitle = xmlDoc.CreateTextNode(item.Title);
                    appendedElementTitle.AppendChild(xmlTextTitle);
                    newelem.AppendChild(appendedElementTitle);
                    xmlDoc.DocumentElement.AppendChild(newelem);

                    // 18
                    // TitleOriginal
                    XmlElement appendedElementTitleOriginal = xmlDoc.CreateElement("TitleOriginal");
                    XmlText xmlTextTitleOriginal = xmlDoc.CreateTextNode(item.TitleOriginal);
                    appendedElementTitleOriginal.AppendChild(xmlTextTitleOriginal);
                    newelem.AppendChild(appendedElementTitleOriginal);
                    xmlDoc.DocumentElement.AppendChild(newelem);

                    // 19
                    // UniqueId
                    XmlElement appendedElementUniqueId = xmlDoc.CreateElement("UniqueId");
                    XmlText xmlTextUniqueId = xmlDoc.CreateTextNode(item.UniqueId);
                    appendedElementUniqueId.AppendChild(xmlTextUniqueId);
                    newelem.AppendChild(appendedElementUniqueId);
                    xmlDoc.DocumentElement.AppendChild(newelem);

                    // 20
                    // Quote
                    XmlElement appendedElementQuote = xmlDoc.CreateElement("Quote");
                    XmlText xmlTextQuote = xmlDoc.CreateTextNode(item.Quote);
                    appendedElementQuote.AppendChild(xmlTextQuote);
                    newelem.AppendChild(appendedElementQuote);
                    xmlDoc.DocumentElement.AppendChild(newelem);

                    // 21
                    // Translator
                    XmlElement appendedElementTranslator = xmlDoc.CreateElement("Translator");
                    XmlText xmlTextTranslator = xmlDoc.CreateTextNode(item.Translator);
                    appendedElementTranslator.AppendChild(xmlTextTranslator);
                    newelem.AppendChild(appendedElementTranslator);
                    xmlDoc.DocumentElement.AppendChild(newelem);

                    // 22
                    // Website
                    XmlElement appendedElementWebsite = xmlDoc.CreateElement("Website");
                    XmlText xmlTextWebsite = xmlDoc.CreateTextNode(item.Website);
                    appendedElementWebsite.AppendChild(xmlTextWebsite);
                    newelem.AppendChild(appendedElementWebsite);
                    xmlDoc.DocumentElement.AppendChild(newelem);

                    // 23
                    // Country
                    XmlElement appendedElementCountry = xmlDoc.CreateElement("Country");
                    XmlText xmlTextCountry = xmlDoc.CreateTextNode(item.Country);
                    appendedElementCountry.AppendChild(xmlTextCountry);
                    newelem.AppendChild(appendedElementCountry);
                    xmlDoc.DocumentElement.AppendChild(newelem);

                    // 24
                    // Books
                    XmlElement appendedElementBooks = xmlDoc.CreateElement("Books");
                    XmlText xmlTextBooks = xmlDoc.CreateTextNode(item.Books);
                    appendedElementBooks.AppendChild(xmlTextBooks);
                    newelem.AppendChild(appendedElementBooks);
                    xmlDoc.DocumentElement.AppendChild(newelem);
                }

                // Determine source folder location
                StorageFolder sourceFolder = await Package.Current.InstalledLocation.GetFolderAsync(Constants.XML_FILE_DIR);
                // Determine destination folder location
                StorageFolder destinationFolder = ApplicationData.Current.LocalFolder;

                try
                {
                    // Create new destination filename
                    StorageFile filename = await destinationFolder.CreateFileAsync(fileNameToUse, CreationCollisionOption.ReplaceExisting);

                    // Store the XML into this new file
                    await xmlDoc.SaveToFileAsync(filename);
                }
                catch
                {
                    saveXMLFileHasFailed = true;
                }

                if (saveXMLFileHasFailed)
                {
                    // Create new source filename
                    StorageFile sourceFilename = await sourceFolder.GetFileAsync(fileNameToUse);
                    // Copy this file to destination location
                    await sourceFilename.CopyAsync(destinationFolder, fileNameToUse, NameCollisionOption.ReplaceExisting);
                }
            }
        }
        #endregion

        #region FetchReviewInfoFromSiteAsync
        public static async Task FetchReviewInfoFromSiteAsync(FWDataItem item)
        {
            var client = new HttpClient();
            client.MaxResponseContentBufferSize = Constants.MAX_RESPONSE_BUFFERSIZE;
            var response = await client.GetAsync(new Uri(item.Link));
            string reviewText = "";

            var stream = await response.Content.ReadAsStreamAsync();
            StreamReader streamReader = new StreamReader(stream);
            reviewText = streamReader.ReadToEnd();

            // Determine publish date
            int startIndex = reviewText.IndexOf("dtreviewed\">");
            int endIndex = reviewText.LastIndexOf("</time>");
            if ((startIndex > 0) && (startIndex < endIndex))
            {
                try
                {
                    item.Added = Convert.ToDateTime(reviewText.Substring(startIndex + 12, endIndex - startIndex - 12));
                }
                catch
                {
                    item.Added = DateTime.Now;
                }
            }

            startIndex = reviewText.IndexOf("<strong>Auteur:</strong>");
            endIndex = reviewText.LastIndexOf("</em></p>");
            if ((startIndex > 0) && (startIndex < endIndex))
            {
                var content = reviewText.Substring(startIndex, endIndex - startIndex + 9);

                // Determine Author
                endIndex = content.IndexOf("<br />");
                if (endIndex > 24)
                {
                    startIndex = content.IndexOf("/auteurs");
                    endIndex = content.IndexOf("\">");
                    item.AuthorLink = content.Substring(startIndex, endIndex - startIndex).Trim();
                    startIndex = endIndex + 2;
                    endIndex = content.IndexOf("</a>");
                    item.Author = content.Substring(startIndex, endIndex - startIndex).Trim();
                }

                // Reposition
                content = content.Substring(endIndex + 2, content.Length - endIndex - 2);

                // Determine Translator
                if (content.Contains("Vertaling"))
                {
                    // Reposition 
                    startIndex = content.IndexOf("Vertaling");
                    content = content.Substring(startIndex, content.Length - startIndex);

                    // Determine Translator
                    startIndex = content.IndexOf("</strong>");
                    endIndex = content.IndexOf("<br />");
                    if (endIndex > startIndex)
                        item.Translator = content.Substring(startIndex + 9, endIndex - startIndex - 9).Trim();

                    // Reposition 
                    content = content.Substring(endIndex, content.Length - endIndex);
                }

                // Determine Publisher
                startIndex = content.IndexOf("\">");
                endIndex = content.IndexOf("</a>");
                if (endIndex > startIndex)
                    item.Publisher = content.Substring(startIndex + 2, endIndex - startIndex - 2).Trim();

                // Reposition 
                startIndex = content.IndexOf("ISBN");
                content = content.Substring(startIndex, content.Length - startIndex);

                // Determine ISBN
                startIndex = content.IndexOf("</strong>");
                endIndex = content.IndexOf("<br />");
                if (endIndex > startIndex)
                    item.ISBN = content.Substring(startIndex + 9, endIndex - startIndex - 9).Trim();

                // Reposition 
                startIndex = content.IndexOf("Uitgave");
                content = content.Substring(startIndex, content.Length - startIndex);

                // Determine Edition
                startIndex = content.IndexOf("</strong>");
                endIndex = content.IndexOf("<br />");
                if (endIndex > startIndex)
                    item.Edition = content.Substring(startIndex + 9, endIndex - startIndex - 9).Trim();

                // Reposition 
                startIndex = content.IndexOf("Verschenen");
                content = content.Substring(startIndex, content.Length - startIndex);

                // Determine PublishDate
                startIndex = content.IndexOf("</strong>");
                endIndex = content.IndexOf("<br />");
                if (endIndex > startIndex)
                    item.PublishDate = content.Substring(startIndex + 9, endIndex - startIndex - 9).Trim();

                // Reposition 
                startIndex = content.IndexOf("Prijs");
                content = content.Substring(startIndex, content.Length - startIndex);

                // Determine Price
                startIndex = content.IndexOf("</strong>");
                endIndex = content.IndexOf("<br />");
                if (endIndex > startIndex)
                    item.Price = content.Substring(startIndex + 9, endIndex - startIndex - 9).Replace("&#8364;", "€").Trim();

                // Reposition 
                content = content.Substring(endIndex, content.Length - endIndex);

                if (content.Contains("Categorie"))
                {
                    // Reposition 
                    startIndex = content.IndexOf("Categorie");
                    content = content.Substring(startIndex, content.Length - startIndex);

                    // Determine Group
                    startIndex = content.IndexOf("</strong>");
                    endIndex = content.IndexOf("<br />");
                    if (endIndex > startIndex)
                    {
                        string category = content.Substring(startIndex + 9, endIndex - startIndex - 9).Trim();
                        switch (category)
                        {
                            case Constants.RSSFEED_VW_TITLE:
                                item.Group = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_VW_CODE));
                                break;
                            case Constants.RSSFEED_KB_TITLE:
                                item.Group = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_KB_CODE));
                                break;
                            case Constants.RSSFEED_YA_TITLE:
                                item.Group = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_YA_CODE));
                                break;
                            case Constants.RSSFEED_GN_TITLE:
                                item.Group = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_GN_CODE));
                                break;
                        }

                    }

                    // Reposition 
                    content = content.Substring(endIndex, content.Length - endIndex);
                }

                if (content.Contains("Leeftijd"))
                {
                    // Reposition 
                    startIndex = content.IndexOf("Leeftijd");
                    content = content.Substring(startIndex, content.Length - startIndex);

                    // Determine Age
                    startIndex = content.IndexOf("</strong>");
                    endIndex = content.IndexOf("<br />");
                    if (endIndex > startIndex)
                        item.Age = content.Substring(startIndex + 9, endIndex - startIndex - 9).Trim();

                    // Reposition 
                    content = content.Substring(endIndex, content.Length - endIndex);
                }

                // Determine Reviewer
                startIndex = content.IndexOf("reviewer");
                string reviewerText = content.Substring(startIndex + 10);
                endIndex = reviewerText.IndexOf("</span>");
                if (endIndex > 0)
                    item.Reviewer = reviewerText.Substring(0, endIndex).Trim();

                // Determine Stars
                startIndex = content.LastIndexOf("images/");
                endIndex = content.LastIndexOf(".png");
                if (endIndex > startIndex)
                    item.SetStars(_baseUri + "Images/" + content.Substring(startIndex + 7, endIndex - startIndex - 7) + ".png");

                // Reposition 
                endIndex = content.IndexOf("Eindoordeel");
                if (endIndex > 0)
                    content = content.Substring(0, endIndex);

                startIndex = content.IndexOf("<br />");
                if (startIndex >= 0)
                    content = content.Substring(startIndex);

                // Determine Quote
                if (content.Contains("<blockquote>") && content.Contains("</blockquote>"))
                {
                    int startQuote = content.IndexOf("<blockquote>");
                    int endQuote = content.IndexOf("</blockquote>");
                    item.Quote = Utility.CleanupNewLines(Utility.CleanupHTML(content.Substring(startQuote + 12, endQuote - startQuote - 12)));

                    // remove quote from Content
                    content = content.Substring(0, startQuote) + content.Substring(endQuote + 13, content.Length - endQuote - 13);
                }

                item.Content = Utility.CleanupNewLines(Utility.CleanupHTML(content));

                // On some occasions the item description was missed. This corrects this issue
                if (item.Description == "")
                    item.Description = item.Content.Substring(0, item.Content.IndexOf("\n\n"));
            }
        }
        #endregion

        #region ReadReviewsFromDisk
        public static void ReadReviewsFromDisk(bool offlineMode)
        {
            bool firstItem = true;

            XmlElement root = _FWFullReviews.DocumentElement;
            XmlNodeList nodes = root.SelectNodes("item");
            foreach (var item in nodes)
            {
                FWDataItem FWItem = new FWDataItem();

                FWItem.Added = Convert.ToDateTime(item.ChildNodes[0].InnerText);
                FWItem.Age = item.ChildNodes[1].InnerText;
                FWItem.Author = item.ChildNodes[2].InnerText;
                FWItem.AuthorLink = item.ChildNodes[3].InnerText;
                FWItem.Content = item.ChildNodes[4].InnerText;
                FWItem.Description = item.ChildNodes[5].InnerText;
                FWItem.Edition = item.ChildNodes[6].InnerText;
                FWItem.Group = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(item.ChildNodes[7].InnerText));
                if (offlineMode)
                    FWItem.SetImage(FWItem.Group.ImageLink);
                else
                    FWItem.SetImage(item.ChildNodes[8].InnerText);
                FWItem.ISBN = item.ChildNodes[9].InnerText;
                FWItem.Link = item.ChildNodes[10].InnerText;
                FWItem.Price = item.ChildNodes[11].InnerText;
                FWItem.PublishDate = item.ChildNodes[12].InnerText;
                FWItem.Publisher = item.ChildNodes[13].InnerText;
                FWItem.Reviewer = item.ChildNodes[14].InnerText;
                FWItem.SetStars(item.ChildNodes[15].InnerText);
                FWItem.SubGenre = item.ChildNodes[16].InnerText;
                FWItem.Title = Utility.CleanupText(Utility.ReplaceSpecialCodes(item.ChildNodes[17].InnerText));
                FWItem.TitleOriginal = Utility.CleanupText(Utility.ReplaceSpecialCodes(item.ChildNodes[18].InnerText));
                FWItem.UniqueId = item.ChildNodes[19].InnerText;
                FWItem.Quote = item.ChildNodes[20].InnerText;
                FWItem.Translator = item.ChildNodes[21].InnerText;
                FWItem.Website = item.ChildNodes[22].InnerText;
                FWItem.Country = item.ChildNodes[23].InnerText;
                FWItem.Books = item.ChildNodes[24].InnerText;

                if (firstItem)
                {
                    Utility.GenerateTile(FWItem);
                    firstItem = false;
                }
                // Show Recent image if (and only if) the item was added more recent than two weeks ago
                FWItem.ShowRecent = FWItem.Added.AddDays(Constants.NR_RECENT_DAYS) > DateTime.Now;

                // Show Recent image if (and only if) the item was added within the last day
                FWItem.ShowNew = FWItem.Added.AddDays(Constants.NR_NEW_DAYS) > DateTime.Now;

                if (FWItem.Group.Items.FirstOrDefault(m => m.UniqueId.Equals(FWItem.UniqueId)) == null)
                {
                    // Item does not exist yet

                    // All fields have been processed
                    // Select the group and add this item to the items in this group
                    _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(FWItem.Group.UniqueId)).Items.Add(FWItem);
                }
            }

            _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_VW_CODE)).Count = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_VW_CODE)).Items.Count();
            _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_YA_CODE)).Count = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_YA_CODE)).Items.Count();
            _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_KB_CODE)).Count = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_KB_CODE)).Items.Count();
            _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_GN_CODE)).Count = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_GN_CODE)).Items.Count();

            _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_SC_CODE)).Count = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_SC_CODE)).Items.Count();
            _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_AR_CODE)).Count = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_AR_CODE)).Items.Count();
            _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_GB_CODE)).Count = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_GB_CODE)).Items.Count();
            _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_IV_CODE)).Count = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_IV_CODE)).Items.Count();
            _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_OR_CODE)).Count = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_OR_CODE)).Items.Count();
            _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.SHORTSTORYFEED_CODE)).Count = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.SHORTSTORYFEED_CODE)).Items.Count();
        }
        #endregion

        #region ProcessCachedReviews
        private static void ProcessCachedReviews()
        {
            bool firstItem = true;

            XmlElement root = _FWFullReviews.DocumentElement;
            XmlNodeList nodes = root.SelectNodes("item"); // You can also use XPath here
            foreach (var item in nodes)
            {
                // use node variable here for your beeds
                String groupId = item.ChildNodes[6].InnerText;
                String title = "";
                switch (groupId)
                {
                    case Constants.RSSFEED_VW_CODE:
                        {
                            title = Constants.RSSFEED_VW_TITLE;
                            break;
                        }
                    case Constants.RSSFEED_YA_CODE:
                        {
                            title = Constants.RSSFEED_YA_TITLE;
                            break;
                        }
                    case Constants.RSSFEED_KB_CODE:
                        {
                            title = Constants.RSSFEED_KB_TITLE;
                            break;
                        }
                    case Constants.RSSFEED_GN_CODE:
                        {
                            title = Constants.RSSFEED_GN_TITLE;
                            break;
                        }
                }
                String themeImagePath = _baseUri + Constants.DEFAULT_IMAGE_PATH + groupId + Constants.DEFAULT_IMAGE_EXTENTION;

                FWDataGroup FWObjectGroup = new FWDataGroup(groupId, title, themeImagePath, "", 0);

                // Only add record to list of groups when it is the first one
                if (_FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(groupId)) == null)
                    _FWDataSource.AllGroups.Add(FWObjectGroup);

                FWDataItem FWItem = new FWDataItem();

                FWItem.Added = Convert.ToDateTime(item.ChildNodes[0].InnerText);
                FWItem.Age = item.ChildNodes[1].InnerText;
                FWItem.Author = item.ChildNodes[2].InnerText;
                FWItem.AuthorLink = item.ChildNodes[3].InnerText;
                FWItem.Content = item.ChildNodes[4].InnerText;
                FWItem.Description = item.ChildNodes[5].InnerText;
                FWItem.Edition = item.ChildNodes[6].InnerText;
                FWItem.Group = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(groupId));
                FWItem.SetImage(themeImagePath);
                FWItem.ISBN = item.ChildNodes[9].InnerText;
                FWItem.Link = item.ChildNodes[10].InnerText;
                FWItem.Price = item.ChildNodes[11].InnerText;
                FWItem.PublishDate = item.ChildNodes[12].InnerText;
                FWItem.Publisher = item.ChildNodes[13].InnerText;
                FWItem.Reviewer = item.ChildNodes[14].InnerText;
                FWItem.SetStars(item.ChildNodes[15].InnerText);
                FWItem.SubGenre = item.ChildNodes[16].InnerText;
                FWItem.Title = Utility.CleanupText(Utility.ReplaceSpecialCodes(item.ChildNodes[17].InnerText));
                FWItem.TitleOriginal = Utility.CleanupText(Utility.ReplaceSpecialCodes(item.ChildNodes[18].InnerText));
                FWItem.UniqueId = item.ChildNodes[19].InnerText;
                FWItem.Quote = item.ChildNodes[20].InnerText;
                FWItem.Translator = item.ChildNodes[21].InnerText;
                //FWItem.Website = item.ChildNodes[22].InnerText;
                //FWItem.Country = item.ChildNodes[23].InnerText;
                //FWItem.Books = item.ChildNodes[24].InnerText;


                if (firstItem)
                {
                    Utility.GenerateTile(FWItem);
                    firstItem = false;
                }

                // All fields have been processed
                // Select the group and add this item to the items in this group
                _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(FWItem.Group.UniqueId)).Items.Add(FWItem);

                _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(FWItem.Group.UniqueId)).Count = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(FWItem.Group.UniqueId)).Items.Count();
            }
        }
        #endregion

        #region CleanupReviewsAsync
        public static async Task CleanupReviewsAsync()
        {
            List<FWDataItem> itemsToProcess = new List<FWDataItem>();

            XmlElement root = _FWFullReviews.DocumentElement;
            XmlNodeList nodes = root.SelectNodes("item");
            foreach (var item in nodes)
            {
                FWDataItem FWItem = new FWDataItem();

                FWItem.Added = Convert.ToDateTime(item.ChildNodes[0].InnerText);
                FWItem.Age = item.ChildNodes[1].InnerText;
                FWItem.Author = item.ChildNodes[2].InnerText;
                FWItem.AuthorLink = item.ChildNodes[3].InnerText;
                FWItem.Content = item.ChildNodes[4].InnerText;
                FWItem.Description = item.ChildNodes[5].InnerText;
                FWItem.Edition = item.ChildNodes[6].InnerText;
                FWItem.Group = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(item.ChildNodes[7].InnerText));
                FWItem.SetImage(item.ChildNodes[8].InnerText);
                FWItem.ISBN = item.ChildNodes[9].InnerText;
                FWItem.Link = item.ChildNodes[10].InnerText;
                FWItem.Price = item.ChildNodes[11].InnerText;
                FWItem.PublishDate = item.ChildNodes[12].InnerText;
                FWItem.Publisher = item.ChildNodes[13].InnerText;
                FWItem.Reviewer = item.ChildNodes[14].InnerText;
                FWItem.SetStars(item.ChildNodes[15].InnerText);
                FWItem.SubGenre = item.ChildNodes[16].InnerText;
                FWItem.Title = Utility.CleanupText(Utility.ReplaceSpecialCodes(item.ChildNodes[17].InnerText));
                FWItem.TitleOriginal = Utility.CleanupText(Utility.ReplaceSpecialCodes(item.ChildNodes[18].InnerText));
                FWItem.UniqueId = item.ChildNodes[19].InnerText;
                FWItem.Quote = item.ChildNodes[20].InnerText;
                FWItem.Translator = item.ChildNodes[21].InnerText;
                FWItem.Website = item.ChildNodes[22].InnerText;
                FWItem.Country = item.ChildNodes[23].InnerText;
                FWItem.Books = item.ChildNodes[24].InnerText;

                // Show Recent image if (and only if) the item was added more recent than two weeks ago
                FWItem.ShowRecent = FWItem.Added.AddDays(Constants.NR_RECENT_DAYS) > DateTime.Now;

                // Show Recent image if (and only if) the item was added within the last day
                FWItem.ShowNew = FWItem.Added.AddDays(Constants.NR_NEW_DAYS) > DateTime.Now;

                if ((FWItem.Group.UniqueId != Constants.BOOKFEED_BD_CODE) && (FWItem.Group.UniqueId != Constants.AUTHORFEED_CODE))
                {
                    itemsToProcess.Add(FWItem);
                }
            }

            await WriteItemsToXMLAsync(Constants.XML_REVIEWS_FILE_NAME, itemsToProcess);
        }
        #endregion

        #region ProcessReviewsAsync
        public static async Task<bool> ProcessReviewsAsync(string feedName, bool updateAll)
        {
            bool newReviewsOnWebsite = false;

            try
            {
                if (updateAll)
                {
                    // All records will be rebuilt, so we start with an empty list
                    _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_VW_CODE)).Items.Clear();
                    _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_YA_CODE)).Items.Clear();
                    _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_KB_CODE)).Items.Clear();
                    _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.RSSFEED_GN_CODE)).Items.Clear();
                }

                // This function is used to initially read all data from the website
                XmlDocument onlineReviewsList = await FetchReviewsInfoAsync(feedName);

                XmlElement root = onlineReviewsList.DocumentElement;
                XmlNodeList nodes = root.SelectNodes("review");

                foreach (var item in nodes)
                {
                    FWDataItem FWItem = new FWDataItem();

                    FWItem.Link = item.ChildNodes[0].InnerText;
                    FWItem.UniqueId = GenerateUniqueIdForReview(FWItem.Link);
                    FWItem.Title = Utility.CleanupText(Utility.ReplaceSpecialCodes(item.ChildNodes[1].InnerText));
                    FWItem.SetImage(item.ChildNodes[2].InnerText);
                    FWItem.Author = item.ChildNodes[4].InnerText;
                    FWItem.SetStars(item.ChildNodes[3].InnerText);

                    // Search on UniqueId
                    var nodeList = _FWFullReviews.GetElementsByTagName("UniqueId");
                    XmlElement node = null;

                    if (nodeList.Count > 0)
                        // Find the node with this id from the review file
                        node = FindNode(nodeList, FWItem.UniqueId);

                    if ((node == null) || updateAll)
                    {
                        // Go to website and fetch full review content 
                        await FetchReviewInfoFromSiteAsync(FWItem);

                        // Add new record to search suggestion list
                        ProcessSuggestions(FWItem);

                        // New item, so set Show New to true
                        FWItem.ShowNew = true;

                        Utility.GenerateTile(FWItem);

                        newReviewsOnWebsite = true;

                        // Show Recent image if (and only if) the item was added more recent than two weeks ago
                        FWItem.ShowRecent = FWItem.Added.AddDays(Constants.NR_RECENT_DAYS) > DateTime.Now;

                        // All fields have been processed

                        if (FWItem.Group.Items.FirstOrDefault(m => m.UniqueId.Equals(FWItem.UniqueId)) == null)
                            // Item does not exist yet
                            // select the group and add this item to the items in this group
                            _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(FWItem.Group.UniqueId)).Items.Insert(0, FWItem);
                        else
                            if (updateAll)
                            {
                                int index = 0;
                                foreach (var existingItem in _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(FWItem.Group.UniqueId)).Items)
                                {
                                    if (existingItem.UniqueId.Equals(FWItem.UniqueId))
                                    {
                                        break;
                                    }
                                    else
                                        index++;
                                }
                                _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(FWItem.Group.UniqueId)).Items.RemoveAt(index);
                                _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(FWItem.Group.UniqueId)).Items.Insert(0, FWItem);
                            }
                    }
                }
            }
            catch { }

            return newReviewsOnWebsite;
        }
        #endregion

        #region FetchReviewsInfoAsync
        public static async Task<XmlDocument> FetchReviewsInfoAsync(string feedName)
        {
            XmlDocument reviewList = new XmlDocument();
            reviewList.LoadXml(Constants.XML_BASE_FILE);

            var client = new HttpClient();
            client.MaxResponseContentBufferSize = Constants.MAX_RESPONSE_BUFFERSIZE;
            var response = await client.GetAsync(new Uri(feedName));

            var stream = await response.Content.ReadAsStreamAsync();
            StreamReader streamReader = new StreamReader(stream);
            string reviewText = streamReader.ReadToEnd();

            int startIndex = reviewText.IndexOf("dotted");
            int endIndex = reviewText.LastIndexOf("</tr></table>") + 5;
            if ((startIndex > 0) && (startIndex < endIndex))
            {
                // Reposition to start of table of reviews
                var content = reviewText.Substring(startIndex + 27, endIndex - startIndex - 27);

                // Loop through all reviews in database
                while (content.Contains("<tr>"))
                {
                    startIndex = content.IndexOf("href=");
                    endIndex = content.IndexOf("</tr>");

                    if (endIndex > startIndex)
                    {
                        var reviewInfo = content.Substring(startIndex, endIndex - startIndex);

                        // Set content to next item in database
                        content = content.Substring(endIndex + 5);

                        XmlElement newelem = reviewList.CreateElement("review");
                        reviewList.DocumentElement.AppendChild(newelem);

                        // 0
                        // Link
                        endIndex = reviewInfo.IndexOf("\">");
                        XmlElement appendedElementLink = reviewList.CreateElement("Link");
                        XmlText xmlTextLink = reviewList.CreateTextNode(reviewInfo.Substring(6, endIndex - 6));
                        appendedElementLink.AppendChild(xmlTextLink);
                        newelem.AppendChild(appendedElementLink);
                        reviewList.DocumentElement.AppendChild(newelem);

                        // Reposition
                        reviewInfo = reviewInfo.Substring(endIndex + 2);

                        // 1
                        // Titel
                        endIndex = reviewInfo.IndexOf("<span>");
                        XmlElement appendedElementTitel = reviewList.CreateElement("Titel");
                        XmlText xmlTextTitel = reviewList.CreateTextNode(reviewInfo.Substring(0, endIndex).Trim());
                        appendedElementTitel.AppendChild(xmlTextTitel);
                        newelem.AppendChild(appendedElementTitel);
                        reviewList.DocumentElement.AppendChild(newelem);

                        // Reposition
                        startIndex = reviewInfo.IndexOf("src=\"");
                        reviewInfo = reviewInfo.Substring(startIndex + 5);

                        // 2
                        // ImageLink
                        endIndex = reviewInfo.IndexOf("\"");
                        XmlElement appendedImageLink = reviewList.CreateElement("ImageLink");
                        XmlText xmlImageLink = reviewList.CreateTextNode(Constants.WEBSITEBASE + reviewInfo.Substring(0, endIndex).Trim());
                        appendedImageLink.AppendChild(xmlImageLink);
                        newelem.AppendChild(appendedImageLink);
                        reviewList.DocumentElement.AppendChild(newelem);

                        // Reposition
                        startIndex = reviewInfo.IndexOf("<td>");
                        reviewInfo = reviewInfo.Substring(startIndex + 4);

                        // 3
                        // Stars
                        endIndex = reviewInfo.IndexOf("</td>");
                        XmlElement appendedElementStars = reviewList.CreateElement("Stars");
                        XmlText xmlTextStars = reviewList.CreateTextNode(reviewInfo.Substring(0, endIndex).Trim());
                        appendedElementStars.AppendChild(xmlTextStars);
                        newelem.AppendChild(appendedElementStars);
                        reviewList.DocumentElement.AppendChild(newelem);

                        // Reposition
                        startIndex = reviewInfo.LastIndexOf("<td>");
                        reviewInfo = reviewInfo.Substring(startIndex + 4);

                        // 4
                        // Author
                        endIndex = reviewInfo.IndexOf("</td>");
                        XmlElement appendedElementAuthor = reviewList.CreateElement("Author");
                        XmlText xmlTextAuthor = reviewList.CreateTextNode(reviewInfo.Substring(0, endIndex).Trim());
                        appendedElementAuthor.AppendChild(xmlTextAuthor);
                        newelem.AppendChild(appendedElementAuthor);
                        reviewList.DocumentElement.AppendChild(newelem);
                    }
                    else
                        // Reached end of usefull data
                        content = "";
                }
            }

            // Check for more (recursively)
            if (reviewText.Contains("pods-pagination-next"))
            {
                reviewText = reviewText.Substring(reviewText.IndexOf("pods-pagination-last"));
                reviewText = reviewText.Substring(reviewText.IndexOf("?pg="));
                endIndex = reviewText.IndexOf("\"");
                XmlDocument additionalReviews = await FetchReviewsInfoAsync(Constants.REVIEWFEED + reviewText.Substring(0, endIndex));

                // Append found items to the list
                XmlElement root = additionalReviews.DocumentElement;
                XmlNodeList nodes = root.SelectNodes("review");
                foreach (var item in nodes)
                {
                    XmlElement newelem = reviewList.CreateElement("review");
                    reviewList.DocumentElement.AppendChild(newelem);

                    // 0
                    // Link
                    XmlElement appendedElementLink = reviewList.CreateElement("Link");
                    XmlText xmlTextLink = reviewList.CreateTextNode(item.ChildNodes[0].InnerText);
                    appendedElementLink.AppendChild(xmlTextLink);
                    newelem.AppendChild(appendedElementLink);
                    reviewList.DocumentElement.AppendChild(newelem);

                    // 1
                    // Titel
                    XmlElement appendedElementTitel = reviewList.CreateElement("Titel");
                    XmlText xmlTextTitel = reviewList.CreateTextNode(item.ChildNodes[1].InnerText);
                    appendedElementTitel.AppendChild(xmlTextTitel);
                    newelem.AppendChild(appendedElementTitel);
                    reviewList.DocumentElement.AppendChild(newelem);

                    // 2
                    // ImageLink
                    XmlElement appendedImageLink = reviewList.CreateElement("ImageLink");
                    XmlText xmlImageLink = reviewList.CreateTextNode(item.ChildNodes[2].InnerText);
                    appendedImageLink.AppendChild(xmlImageLink);
                    newelem.AppendChild(appendedImageLink);
                    reviewList.DocumentElement.AppendChild(newelem);

                    // 3
                    // Stars
                    XmlElement appendedElementStars = reviewList.CreateElement("Stars");
                    XmlText xmlTextStars = reviewList.CreateTextNode(item.ChildNodes[3].InnerText);
                    appendedElementStars.AppendChild(xmlTextStars);
                    newelem.AppendChild(appendedElementStars);
                    reviewList.DocumentElement.AppendChild(newelem);

                    // 4
                    // Author
                    XmlElement appendedElementAuthor = reviewList.CreateElement("Author");
                    XmlText xmlTextAuthor = reviewList.CreateTextNode(item.ChildNodes[4].InnerText);
                    appendedElementAuthor.AppendChild(xmlTextAuthor);
                    newelem.AppendChild(appendedElementAuthor);
                    reviewList.DocumentElement.AppendChild(newelem);
                }
            }
            return reviewList;
        }
        #endregion

        #endregion

        #region Handle Books

        #region ProcessBooksAsync
        public static async Task<bool> ProcessBooksAsync(string feedName, string groupId)
        {
            bool newBooksOnWebsite = false;

            // This function is used to initially read all data from the website
            XmlDocument onlineBooksDatabase = await FetchBooksInfoAsync(feedName);

            XmlElement root = onlineBooksDatabase.DocumentElement;
            XmlNodeList nodes = root.SelectNodes("book");
            foreach (var item in nodes)
            {
                FWDataItem FWItem = new FWDataItem();

                FWItem.Link = item.ChildNodes[0].InnerText;
                FWItem.UniqueId = Constants.BOOKFEED_BD_CODE + "-" + item.ChildNodes[0].InnerText.Substring(item.ChildNodes[0].InnerText.LastIndexOf("/") + 1);
                FWItem.Title = Utility.CleanupText(Utility.ReplaceSpecialCodes(item.ChildNodes[1].InnerText));
                FWItem.Author = item.ChildNodes[2].InnerText;
                FWItem.PublishDate = item.ChildNodes[3].InnerText;

                // Determine Group
                FWItem.Group = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(groupId));

                // Search on UniqueId
                var nodeList = _FWBookDatabase.GetElementsByTagName("UniqueId");
                XmlElement node = null;

                if (nodeList.Count > 0)
                    // Find the node with this id from the review file
                    node = FindNode(nodeList, FWItem.UniqueId);

                if (node != null)
                {
                    FWItem.Added = Convert.ToDateTime(node.ParentNode.ChildNodes[0].InnerText);
                    FWItem.Age = node.ParentNode.ChildNodes[1].InnerText;
                    FWItem.Author = node.ParentNode.ChildNodes[2].InnerText;
                    FWItem.AuthorLink = node.ParentNode.ChildNodes[3].InnerText;
                    FWItem.Content = node.ParentNode.ChildNodes[4].InnerText;
                    FWItem.Description = node.ParentNode.ChildNodes[5].InnerText;
                    FWItem.Edition = node.ParentNode.ChildNodes[6].InnerText;
                    FWItem.SetImage(node.ParentNode.ChildNodes[8].InnerText);
                    FWItem.ISBN = node.ParentNode.ChildNodes[9].InnerText;
                    FWItem.Price = node.ParentNode.ChildNodes[11].InnerText;
                    FWItem.PublishDate = node.ParentNode.ChildNodes[12].InnerText;
                    FWItem.Publisher = node.ParentNode.ChildNodes[13].InnerText;
                    FWItem.Reviewer = node.ParentNode.ChildNodes[14].InnerText;
                    FWItem.SetStars(node.ParentNode.ChildNodes[15].InnerText);
                    FWItem.SubGenre = node.ParentNode.ChildNodes[16].InnerText;
                    FWItem.TitleOriginal = Utility.CleanupText(Utility.ReplaceSpecialCodes(node.ParentNode.ChildNodes[18].InnerText));
                }
                else
                {
                    // Go to website and fetch full book content 
                    await FetchBookInfoFromSiteAsync(FWItem);

                    // Add new record to search suggestion list
                    ProcessSuggestions(FWItem);

                    newBooksOnWebsite = true;
                }

                bool isInCollection = false;
                foreach (var existingItem in _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(FWItem.Group.UniqueId)).Items)
                {
                    if (existingItem.UniqueId.Equals(FWItem.UniqueId))
                    {
                        isInCollection = true;
                        break;
                    }
                }

                if (!isInCollection)
                {
                    // All fields have been processed
                    // Select the group and add this item to the items in this group
                    _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(FWItem.Group.UniqueId)).Items.Add(FWItem);

                    // Determine the number of items in this group
                    _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(FWItem.Group.UniqueId)).Count = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(FWItem.Group.UniqueId)).Items.Count();
                }
            }

            return newBooksOnWebsite;
        }
        #endregion

        #region FetchBooksInfoAsync
        public static async Task<XmlDocument> FetchBooksInfoAsync(string feedName)
        {
            XmlDocument bookDatabase = new XmlDocument();
            bookDatabase.LoadXml(Constants.XML_BASE_FILE);

            var client = new HttpClient();
            client.MaxResponseContentBufferSize = Constants.MAX_RESPONSE_BUFFERSIZE;
            var response = await client.GetAsync(new Uri(feedName));

            var stream = await response.Content.ReadAsStreamAsync();
            StreamReader streamReader = new StreamReader(stream);
            string reviewText = streamReader.ReadToEnd();

            int startIndex = reviewText.IndexOf("dotted");
            int endIndex = reviewText.LastIndexOf("</tr></table>") + 5;
            if ((startIndex > 0) && (startIndex < endIndex))
            {
                // Reposition to start of table of books
                var content = reviewText.Substring(startIndex + 27, endIndex - startIndex - 27);

                // Correct site error dd 4-1-2014
                content = content.Replace("</td><tr>", "</td></tr><tr>");

                // Loop through all books in database
                while (content.Contains("<tr>"))
                {
                    startIndex = content.IndexOf("href=");
                    //endIndex = content.IndexOf("</tr>");
                    endIndex = content.IndexOf("</tr>");

                    if (endIndex > startIndex)
                    {
                        var bookInfo = content.Substring(startIndex, endIndex - startIndex);

                        // Set content to next item in database
                        content = content.Substring(endIndex + 5);

                        XmlElement newelem = bookDatabase.CreateElement("book");
                        bookDatabase.DocumentElement.AppendChild(newelem);

                        // 0
                        // Link
                        endIndex = bookInfo.IndexOf("\">");
                        XmlElement appendedElementLink = bookDatabase.CreateElement("Link");
                        XmlText xmlTextLink = bookDatabase.CreateTextNode(Constants.WEBSITEBASE + "/" + bookInfo.Substring(6, endIndex - 6));
                        appendedElementLink.AppendChild(xmlTextLink);
                        newelem.AppendChild(appendedElementLink);
                        bookDatabase.DocumentElement.AppendChild(newelem);

                        // Reposition
                        bookInfo = bookInfo.Substring(endIndex + 2);

                        // 1
                        // Titel
                        endIndex = bookInfo.IndexOf("<span>");
                        XmlElement appendedElementTitel = bookDatabase.CreateElement("Titel");
                        XmlText xmlTextTitel = bookDatabase.CreateTextNode(bookInfo.Substring(0, endIndex).Trim());
                        appendedElementTitel.AppendChild(xmlTextTitel);
                        newelem.AppendChild(appendedElementTitel);
                        bookDatabase.DocumentElement.AppendChild(newelem);

                        // Reposition
                        startIndex = bookInfo.IndexOf("<td>");
                        bookInfo = bookInfo.Substring(startIndex + 4);

                        // 2
                        // Author
                        endIndex = bookInfo.IndexOf("</td>");
                        XmlElement appendedElementAuthor = bookDatabase.CreateElement("Author");
                        XmlText xmlTextAuthor = bookDatabase.CreateTextNode(bookInfo.Substring(0, endIndex).Trim());
                        appendedElementAuthor.AppendChild(xmlTextAuthor);
                        newelem.AppendChild(appendedElementAuthor);
                        bookDatabase.DocumentElement.AppendChild(newelem);

                        // Reposition
                        startIndex = bookInfo.LastIndexOf("<td>");
                        bookInfo = bookInfo.Substring(startIndex + 4);

                        // 3
                        // Published
                        endIndex = bookInfo.IndexOf("</td>");
                        XmlElement appendedElementPublished = bookDatabase.CreateElement("Published");
                        XmlText xmlTextPublished = bookDatabase.CreateTextNode(bookInfo.Substring(0, endIndex).Trim());
                        appendedElementPublished.AppendChild(xmlTextPublished);
                        newelem.AppendChild(appendedElementPublished);
                        bookDatabase.DocumentElement.AppendChild(newelem);
                    }
                    else
                        // Reached end of usefull data
                        content = "";
                }
            }

            // Check for more (recursively)
            if (reviewText.Contains("pods-pagination-next"))
            {
                reviewText = reviewText.Substring(reviewText.IndexOf("pods-pagination-last"));
                reviewText = reviewText.Substring(reviewText.IndexOf("?pg="));
                endIndex = reviewText.IndexOf("\"");
                XmlDocument additionalReviews = await FetchBooksInfoAsync(Constants.BOOKFEED + reviewText.Substring(0, endIndex));

                // Append found items to the list
                XmlElement root = additionalReviews.DocumentElement;
                XmlNodeList nodes = root.SelectNodes("book");
                foreach (var item in nodes)
                {
                    XmlElement newelem = bookDatabase.CreateElement("book");
                    bookDatabase.DocumentElement.AppendChild(newelem);

                    // 0
                    // Link
                    XmlElement appendedElementLink = bookDatabase.CreateElement("Link");
                    XmlText xmlTextLink = bookDatabase.CreateTextNode(item.ChildNodes[0].InnerText);
                    appendedElementLink.AppendChild(xmlTextLink);
                    newelem.AppendChild(appendedElementLink);
                    bookDatabase.DocumentElement.AppendChild(newelem);

                    // 1
                    // Titel
                    XmlElement appendedElementTitel = bookDatabase.CreateElement("Titel");
                    XmlText xmlTextTitel = bookDatabase.CreateTextNode(item.ChildNodes[1].InnerText);
                    appendedElementTitel.AppendChild(xmlTextTitel);
                    newelem.AppendChild(appendedElementTitel);
                    bookDatabase.DocumentElement.AppendChild(newelem);

                    // 2
                    // Author
                    XmlElement appendedElementAuthor = bookDatabase.CreateElement("Author");
                    XmlText xmlTextAuthor = bookDatabase.CreateTextNode(item.ChildNodes[2].InnerText);
                    appendedElementAuthor.AppendChild(xmlTextAuthor);
                    newelem.AppendChild(appendedElementAuthor);
                    bookDatabase.DocumentElement.AppendChild(newelem);

                    // 3
                    // Published
                    XmlElement appendedElementPublished = bookDatabase.CreateElement("Published");
                    XmlText xmlTextPublished = bookDatabase.CreateTextNode(item.ChildNodes[3].InnerText);
                    appendedElementPublished.AppendChild(xmlTextPublished);
                    newelem.AppendChild(appendedElementPublished);
                    bookDatabase.DocumentElement.AppendChild(newelem);
                }
            }
            return bookDatabase;
        }
        #endregion

        #region FetchBookInfoFromSiteAsync
        public static async Task FetchBookInfoFromSiteAsync(FWDataItem item)
        {
            var client = new HttpClient();
            client.MaxResponseContentBufferSize = Constants.MAX_RESPONSE_BUFFERSIZE;
            var response = await client.GetAsync(new Uri(item.Link));

            var stream = await response.Content.ReadAsStreamAsync();
            StreamReader streamReader = new StreamReader(stream);
            string reviewText = streamReader.ReadToEnd();

            int startIndex = reviewText.IndexOf("boekvak");
            int endIndex = reviewText.IndexOf("disqus_thread");
            if ((startIndex > 0) && (startIndex < endIndex))
            {
                var content = reviewText.Substring(startIndex, endIndex - startIndex);

                // Determine Image
                startIndex = content.IndexOf(" src=");
                endIndex = content.IndexOf(".jpg");
                if (endIndex > 6)
                {
                    if (content.Substring(startIndex + 6, endIndex - startIndex - 2).StartsWith("/wp"))
                        item.SetImage(Constants.WEBSITEBASE + content.Substring(startIndex + 6, endIndex - startIndex - 2));
                    else
                        item.SetImage(content.Substring(startIndex + 6, endIndex - startIndex - 2));
                }
                // Reposition
                startIndex = content.IndexOf("Titel origineel:");
                content = content.Substring(startIndex + 20);

                // Determine Titel Origineel
                endIndex = content.IndexOf("<br /><br />");
                if (endIndex > 10)
                    item.TitleOriginal = Utility.CleanupText(Utility.ReplaceSpecialCodes(content.Substring(0, endIndex).Trim()));

                // Reposition
                startIndex = content.IndexOf("Uitgever:");
                content = content.Substring(startIndex + 13);

                // Determine Publisher
                endIndex = content.IndexOf("<br /><br />");
                if (endIndex > 0)
                {
                    item.Publisher = content.Substring(0, endIndex).Trim();
                    item.Publisher = item.Publisher.Substring(item.Publisher.IndexOf("\">") + 2, item.Publisher.IndexOf("</a>") - item.Publisher.IndexOf("\">") - 2);
                }

                // Reposition 
                startIndex = content.IndexOf("ISBN:");
                content = content.Substring(startIndex);

                // Determine ISBN
                endIndex = content.IndexOf("<br /><br />");
                if (endIndex > 0)
                    item.ISBN = Utility.CleanupHTML(content.Substring(5, endIndex)).Trim();

                // Reposition 
                startIndex = content.IndexOf("Subgenre:");
                content = content.Substring(startIndex + 13);

                // Determine Subgenre
                endIndex = content.IndexOf("<br");
                if (endIndex > 0)
                    item.SubGenre = Utility.CleanupHTML(content.Substring(0, endIndex).Trim().Replace("&amp;", "&"));

                // Reposition 
                startIndex = content.IndexOf("dotted");
                content = content.Substring(startIndex + 8);

                // Determine Description
                endIndex = content.IndexOf("Boeken van deze auteur");
                if (endIndex > 0)
                    item.Content = Utility.CleanupNewLines(Utility.CleanupHTML(content.Substring(0, endIndex)));

                // Reposition 
                startIndex = content.IndexOf("Boeken van deze auteur");
                if (startIndex > 0)
                {
                    content = content.Substring(startIndex);
                    startIndex = content.IndexOf("href=");
                    while (startIndex > 0)
                    {
                        endIndex = content.IndexOf("</a>");
                        string otherBookInfo = content.Substring(startIndex + 6, endIndex - startIndex - 6);
                        content = content.Substring(endIndex + 4);

                        if (!otherBookInfo.StartsWith("/boeken_volledig"))
                            item.Books = item.Books + otherBookInfo.Substring(0, otherBookInfo.IndexOf(">") - 1) + "|" + otherBookInfo.Substring(otherBookInfo.IndexOf("/wp"), otherBookInfo.IndexOf(".jpg") - otherBookInfo.IndexOf("/wp") + 4) + "|";

                        startIndex = content.IndexOf("href=");
                    }
                }
            }
        }
        #endregion

        #region ReadBooksFromDisk
        public static void ReadBooksFromDisk(string groupId, bool offlineMode)
        {
            if (!booksReadFromDisk)
            {
                bool firstItem = true;

                XmlElement root = _FWBookDatabase.DocumentElement;
                XmlNodeList nodes = root.SelectNodes("item");
                foreach (var item in nodes)
                {
                    FWDataItem FWItem = new FWDataItem();

                    FWItem.Added = Convert.ToDateTime(item.ChildNodes[0].InnerText);
                    FWItem.Age = item.ChildNodes[1].InnerText;
                    FWItem.Author = item.ChildNodes[2].InnerText;
                    FWItem.AuthorLink = item.ChildNodes[3].InnerText;
                    FWItem.Content = item.ChildNodes[4].InnerText;
                    FWItem.Description = ""; // item.ChildNodes[5].InnerText;
                    FWItem.Edition = item.ChildNodes[6].InnerText;
                    FWItem.Group = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(groupId));
                    if (offlineMode)
                        FWItem.SetImage(FWItem.Group.ImageLink);
                    else
                        FWItem.SetImage(item.ChildNodes[8].InnerText);
                    FWItem.ISBN = item.ChildNodes[9].InnerText;
                    FWItem.Link = item.ChildNodes[10].InnerText;
                    FWItem.Price = item.ChildNodes[11].InnerText;
                    FWItem.PublishDate = item.ChildNodes[12].InnerText;
                    FWItem.Publisher = item.ChildNodes[13].InnerText;
                    FWItem.Reviewer = item.ChildNodes[14].InnerText;
                    FWItem.SetStars(item.ChildNodes[15].InnerText);
                    FWItem.SubGenre = item.ChildNodes[16].InnerText;
                    FWItem.Title = Utility.CleanupText(Utility.ReplaceSpecialCodes(item.ChildNodes[17].InnerText));
                    FWItem.TitleOriginal = Utility.CleanupText(Utility.ReplaceSpecialCodes(item.ChildNodes[18].InnerText));
                    FWItem.UniqueId = item.ChildNodes[19].InnerText;

                    if (firstItem)
                    {
                        Utility.GenerateTile(FWItem);
                        firstItem = false;
                    }
                    // Show Recent image if (and only if) the item was added more recent than two weeks ago
                    FWItem.ShowRecent = FWItem.Added.AddDays(Constants.NR_RECENT_DAYS) > DateTime.Now;

                    // Show Recent image if (and only if) the item was added within the last day
                    FWItem.ShowNew = FWItem.Added.AddDays(Constants.NR_NEW_DAYS) > DateTime.Now;

                    if (FWItem.Group.Items.FirstOrDefault(m => m.UniqueId.Equals(FWItem.UniqueId)) == null)
                    {
                        // Item does not exist yet
                        // All fields have been processed
                        // Select the group and add this item to the items in this group
                        _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(FWItem.Group.UniqueId)).Items.Add(FWItem);
                    }
                }

                _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.BOOKFEED_BD_CODE)).Count = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.BOOKFEED_BD_CODE)).Items.Count();

                booksReadFromDisk = true;
            }
        }
        #endregion

        #endregion

        #region Handle other RSS Feeds

        #region ProcessBasicFeedAsync
        private static async Task<bool> ProcessBasicFeedAsync(string feedName, string groupId)
        {
            bool newItemsOnWebsite = false;

            try
            {
                var myFeed = await Utility.GetRSSFeedAsync(feedName);

                foreach (var channel in myFeed)
                {
                    foreach (var item in channel.Items)
                    {
                        var noError = true;

                        FWDataItem FWItem = new FWDataItem();

                        // Determine Group
                        FWItem.Group = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(groupId));

                        // Determine Url
                        FWItem.Link = item.Link;

                        // Determine UniqueId
                        FWItem.UniqueId = GenerateUniqueIdForReview(FWItem.Link);

                        // Search on UniqueId
                        var nodeList = _FWFullReviews.GetElementsByTagName("UniqueId");
                        XmlElement node = null;

                        if (nodeList.Count > 0)
                            // Find the node with this id from the review file
                            node = FindNode(nodeList, FWItem.UniqueId);

                        if (node != null)
                        {
                            FWItem.Added = Convert.ToDateTime(node.ParentNode.ChildNodes[0].InnerText);
                            FWItem.Content = node.ParentNode.ChildNodes[3].InnerText;
                            FWItem.Description = node.ParentNode.ChildNodes[5].InnerText;
                            FWItem.SetImage(node.ParentNode.ChildNodes[8].InnerText);
                            FWItem.Title = Utility.CleanupText(Utility.ReplaceSpecialCodes(node.ParentNode.ChildNodes[17].InnerText));
                        }
                        else
                        {
                            // Fetch data from feed record
                            FWItem.Title = Utility.CleanupText(Utility.ReplaceSpecialCodes(item.Title));

                            int startIndex = item.Description.IndexOf(Constants.FIND_IMG_TAG_START);
                            int endIndex = item.Description.IndexOf(Constants.FIND_IMG_TAG_END1) + Constants.FIND_IMG_TAG_END1.Length;
                            if ((startIndex > 0) && (endIndex > Constants.FIND_IMG_TAG_END1.Length) && (startIndex < endIndex))
                            {
                                // Image found in description
                                FWItem.SetImage(item.Description.Substring(startIndex, endIndex - startIndex));

                                int end2Index = item.Description.IndexOf(Constants.FIND_IMG_TAG_END2) + 1;
                                string content = Utility.StripHTMLTags(item.Description.Substring(end2Index, item.Description.Length - end2Index));

                                FWItem.Description = Utility.CleanupText(Utility.CleanupHTML(content));
                            }
                            else
                            {
                                // Default image selected
                                FWItem.SetImage(FWItem.Group.ImageLink);
                                FWItem.Description = Utility.CleanupText(Utility.CleanupHTML(Utility.StripHTMLTags(item.Description)));
                            }

                            // Fetch remaining data from webserver
                            noError = await FetchHTMLFromSiteAsync(FWItem);

                            if (noError)
                            {
                                // Add new record to search suggestion list
                                ProcessSuggestions(FWItem);

                                // New item, so set Show New to true
                                FWItem.ShowNew = true;

                                newItemsOnWebsite = true;
                            }
                        }

                        if (noError)
                        {
                            // Show Recent image if (and only if) the item was added more recent than two weeks ago
                            FWItem.ShowRecent = FWItem.Added.AddDays(Constants.NR_RECENT_DAYS) > DateTime.Now;

                            // All fields have been processed

                            if (FWItem.Group.Items.FirstOrDefault(m => m.UniqueId.Equals(FWItem.UniqueId)) == null)
                            {
                                // Item does not exist yet

                                // select the group and add this item to the items in this group
                                _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(FWItem.Group.UniqueId)).Items.Insert(0, FWItem);
                            }
                        }
                    }
                }
            }
            catch { }

            return newItemsOnWebsite;
        }
        #endregion

        #region ProcessDoubleFeedAsync
        private static async Task<bool> ProcessDoubleFeedAsync(string feedName, string feedName2, string groupId)
        {
            return await ProcessBasicFeedAsync(feedName, groupId) && await ProcessBasicFeedAsync(feedName2, groupId);
        }
        #endregion

        #region FetchHTMLFromSiteAsync
        private static async Task<bool> FetchHTMLFromSiteAsync(FWDataItem item)
        {
            var noError = true;

            var client = new HttpClient();
            client.MaxResponseContentBufferSize = Constants.MAX_RESPONSE_BUFFERSIZE;
            var response = await client.GetAsync(new Uri(item.Link));
            string pageHTML = "";

            var stream = await response.Content.ReadAsStreamAsync();
            StreamReader streamReader = new StreamReader(stream);
            pageHTML = streamReader.ReadToEnd();

            var content = "";

            // Global position of content on page
            int startIndex = pageHTML.IndexOf("site-main");
            int endIndex = pageHTML.LastIndexOf("<div id=\"disqus_thread");
            if (endIndex < 0)
                endIndex = pageHTML.LastIndexOf("yarpp-related");

            if ((startIndex > 0) && (startIndex < endIndex))
                content = pageHTML.Substring(startIndex, endIndex - startIndex);

            // Precise position of content on page
            startIndex = content.IndexOf("<article");
            if (startIndex < 0)
                startIndex = content.IndexOf("<p>");
            if (startIndex < 0)
                startIndex = content.IndexOf("<div");

            endIndex = content.IndexOf("</article>");
            if (endIndex > 0)
                endIndex += 10;
            if (endIndex < 0)
                endIndex = content.LastIndexOf(">") + 1;

            if (endIndex > 0)
            {
                if ((startIndex > 0) && (startIndex < endIndex))
                    content = content.Substring(startIndex, endIndex - startIndex);
                else
                    content = "";
            }
            else
                if (startIndex > 0)
                    content = content.Substring(startIndex);
                else
                    content = "";

            if (content.Length == 0)
            {
                noError = false;
                return noError;
            }

            content = "<html lang=\"nl-NL\"><head>" + Constants.CSS1 + Constants.CSS2 + Constants.CSS3
                + "</head><body>" + content + "</body></html>";

            content = content.Replace("\"/wp-content", "\"" + Constants.WEBSITEBASE + "/wp-content");
            content = content.Replace("'/wp-content", "'" + Constants.WEBSITEBASE + "/wp-content");

            // Correct wrong youtube include link
            content = content.Replace("src='//", "src='http://");

            item.Content = content;

            return noError;
        }
        #endregion

        #region LoadFacebookFeedAsync
        /// <summary>
        /// This function reads a facebook feed.
        /// In this app it is unused however
        /// </summary>
        /// <returns>JsonArray</returns>
        public static async Task<JsonArray> loadFacebookFeedAsync()
        {
            //
            // Retrieve Facebook data
            //
            var client = new HttpClient();
            client.MaxResponseContentBufferSize = Constants.MAX_RESPONSE_BUFFERSIZE;
            client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12");

            //
            // get the content form the URL
            //
            var response = await client.GetAsync(new Uri(Constants.JSONFEED_FACEBOOK));
            var result = await response.Content.ReadAsStringAsync();

            try
            {
                // Parse the JSON mediaObject data
                return JsonArray.Parse(result);
            }
            catch
            {
                return null;
            }
        }
        #endregion

        #region LoadNewsFeedAsync
        /// <summary>
        /// Read and store the newsfeed 
        /// </summary>
        /// <param name="feedName"></param>
        /// <param name="_allReviews"></param>
        /// <returns></returns>
        public static async Task LoadNewsFeedAsync()
        {
            try
            {
                var myFeed = await Utility.GetRSSFeedAsync(Constants.RSSFEED_LATEST);

                XmlDocument newsList = new XmlDocument();

                newsList.LoadXml(Constants.XML_BASE_FILE);

                foreach (var channel in myFeed)
                {
                    foreach (var item in channel.Items)
                    {
                        // Create a new root node
                        XmlElement root = newsList.DocumentElement;
                        XmlElement newElem = newsList.CreateElement("news");
                        root.AppendChild(newElem);

                        // Create an element node for description
                        XmlElement newElemDetail = newsList.CreateElement("newsContent");
                        newElemDetail.InnerText = Utility.CleanupHTML(item.Description);
                        newElem.AppendChild(newElemDetail);

                        // Create an new element node for publication date
                        newElemDetail = newsList.CreateElement("newsDate");
                        if (item.pubDate != "")
                        {
                            var myDate = Convert.ToDateTime(item.pubDate);
                            newElemDetail.InnerText = myDate.ToString("dd-MM-yyyy");
                        }
                        else
                            newElemDetail.InnerText = "";
                        newElem.AppendChild(newElemDetail);

                        // Create an new element node for link
                        newElemDetail = newsList.CreateElement("newsLink");
                        newElemDetail.InnerText = item.Link;
                        newElem.AppendChild(newElemDetail);

                        // Create an element node for title
                        newElemDetail = newsList.CreateElement("newsTitle");
                        newElemDetail.InnerText = Utility.CleanupText(Utility.ReplaceSpecialCodes(item.Title));
                        newElem.AppendChild(newElemDetail);
                    }
                }

                UpdateNews(newsList);
            }
            catch
            {

            }
        }
        #endregion

        #endregion

        #region Handle Authors

        #region ProcessAuthorsAsync
        public static async Task<bool> ProcessAuthorsAsync(string uniqueId = null)
        {
            bool newAuthorsOnWebsite = false;

            try
            {
                bool updateAll = (uniqueId != null);

                // This function is used to initially read all data from the website
                XmlDocument onlineAuthorsDatabase = await FetchAuthorsInfoAsync(Constants.AUTHORFEED);

                XmlElement root = onlineAuthorsDatabase.DocumentElement;
                XmlNodeList nodes = root.SelectNodes("author");

                // Long running task
                int counter = 0;

                foreach (var item in nodes)
                {
                    FWDataItem FWItem = new FWDataItem();

                    FWItem.Link = item.ChildNodes[0].InnerText;
                    FWItem.AuthorLink = item.ChildNodes[0].InnerText;
                    FWItem.UniqueId = Constants.AUTHORFEED_CODE + "-" + item.ChildNodes[0].InnerText.Substring(item.ChildNodes[0].InnerText.LastIndexOf("/") + 1);
                    FWItem.Author = Utility.CleanupText(Utility.ReplaceSpecialCodes(item.ChildNodes[1].InnerText));
                    FWItem.Country = item.ChildNodes[2].InnerText;

                    if (
                        ((uniqueId != null) && (FWItem.UniqueId == uniqueId))
                        ||
                        (uniqueId == null)
                       )
                    {
                        // Determine Group
                        FWItem.Group = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.AUTHORFEED_CODE));

                        // Search on UniqueId
                        var nodeList = _FWAuthorDatabase.GetElementsByTagName("UniqueId");
                        XmlElement node = null;

                        if (nodeList.Count > 0)
                            // Find the node with this id from the review file
                            node = FindNode(nodeList, FWItem.UniqueId);

                        if (node != null)
                        {
                            FWItem.Added = Convert.ToDateTime(node.ParentNode.ChildNodes[0].InnerText);
                            FWItem.Age = node.ParentNode.ChildNodes[1].InnerText;
                            FWItem.Author = node.ParentNode.ChildNodes[2].InnerText;
                            FWItem.AuthorLink = node.ParentNode.ChildNodes[3].InnerText;
                            FWItem.Content = node.ParentNode.ChildNodes[4].InnerText;
                            FWItem.Description = node.ParentNode.ChildNodes[5].InnerText;
                            FWItem.Edition = node.ParentNode.ChildNodes[6].InnerText;
                            FWItem.SetImage(node.ParentNode.ChildNodes[8].InnerText);
                            FWItem.ISBN = node.ParentNode.ChildNodes[9].InnerText;
                            FWItem.Price = node.ParentNode.ChildNodes[11].InnerText;
                            FWItem.PublishDate = node.ParentNode.ChildNodes[12].InnerText;
                            FWItem.Publisher = node.ParentNode.ChildNodes[13].InnerText;
                            FWItem.Reviewer = node.ParentNode.ChildNodes[14].InnerText;
                            FWItem.SetStars(node.ParentNode.ChildNodes[15].InnerText);
                            FWItem.SubGenre = node.ParentNode.ChildNodes[16].InnerText;
                            FWItem.Title = Utility.CleanupText(Utility.ReplaceSpecialCodes(node.ParentNode.ChildNodes[17].InnerText));
                            FWItem.TitleOriginal = Utility.CleanupText(Utility.ReplaceSpecialCodes(node.ParentNode.ChildNodes[18].InnerText));
                            FWItem.Quote = node.ParentNode.ChildNodes[20].InnerText;
                            FWItem.Translator = node.ParentNode.ChildNodes[21].InnerText;
                            FWItem.Website = node.ParentNode.ChildNodes[22].InnerText;
                            FWItem.Country = node.ParentNode.ChildNodes[23].InnerText;
                            FWItem.Books = node.ParentNode.ChildNodes[24].InnerText;

                            // Codeblock when updates to the non existing images must be determined again
                            if (
                                ((FWItem.Books == "") || (FWItem.Content.Length == 0) || FWItem.ImageLink.ToLower().Contains("onbekend"))
                                ||
                                updateAll
                               )
                            {
                                // Go to website and fetch full author content 
                                await FetchAuthorInfoFromSiteAsync(FWItem, updateAll);

                                // Add new record to search suggestion list
                                ProcessSuggestions(FWItem);

                                newAuthorsOnWebsite = true;

                                counter++;
                            }
                        }
                        else
                        {
                            // Go to website and fetch full author content 
                            await FetchAuthorInfoFromSiteAsync(FWItem, updateAll);

                            // Add new record to search suggestion list
                            ProcessSuggestions(FWItem);

                            newAuthorsOnWebsite = true;

                            counter++;
                        }

                        bool isInCollection = false;
                        int index = 0;
                        foreach (var existingItem in _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(FWItem.Group.UniqueId)).Items)
                        {
                            if (existingItem.UniqueId.Equals(FWItem.UniqueId))
                            {
                                isInCollection = true;
                                break;
                            }
                            else
                                index++;
                        }

                        if (!isInCollection)
                        {
                            // All fields have been processed
                            // Select the group and add this item to the items in this group
                            _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(FWItem.Group.UniqueId)).Items.Add(FWItem);

                            // Determine the number of items in this group
                            _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(FWItem.Group.UniqueId)).Count = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(FWItem.Group.UniqueId)).Items.Count();
                        }
                        else
                        {
                            // Codeblock when updating existing records becomes necessary
                            _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(FWItem.Group.UniqueId)).Items.RemoveAt(index);
                            _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(FWItem.Group.UniqueId)).Items.Insert(0, FWItem);
                        }

                        if (counter > Constants.MAX_NR_AUTHORS_TO_UPDATE)
                            break;
                    }
                }
            }
            catch { }

            return newAuthorsOnWebsite;
        }
        #endregion

        #region ProcessOneAuthorAsync
        public static async Task ProcessOneAuthorAsync(string uniqueId)
        {
            if (await ProcessAuthorsAsync(uniqueId))
            {
                // Reload data in the app
                try
                {
                    Utility.SendNotification(Constants.MESSAGE_NOTIFICATION_HEADER, Constants.MESSAGE_NOTIFICATION_UPDATE_AUTHOR, Constants.NOTIFICATION_AUTHORS);
                    await Utility.ReloadAppData();
                }
                catch
                {
                }
            }
            else
                Utility.SendNotification(Constants.MESSAGE_NOTIFICATION_HEADER, Constants.MESSAGE_NOTIFICATION_UPDATE_NO_AUTHOR, Constants.NOTIFICATION_AUTHORS);
        }
        #endregion

        #region FetchAuthorsInfoAsync
        public static async Task<XmlDocument> FetchAuthorsInfoAsync(string feedName)
        {
            XmlDocument authorDatabase = new XmlDocument();
            authorDatabase.LoadXml(Constants.XML_BASE_FILE);

            var client = new HttpClient();
            client.MaxResponseContentBufferSize = Constants.MAX_RESPONSE_BUFFERSIZE;
            var response = await client.GetAsync(new Uri(feedName));

            var stream = await response.Content.ReadAsStreamAsync();
            StreamReader streamReader = new StreamReader(stream);
            string reviewText = streamReader.ReadToEnd();

            int startIndex = reviewText.IndexOf("dotted");
            int endIndex = reviewText.LastIndexOf("</table>") - 5;
            if ((startIndex > 0) && (startIndex < endIndex))
            {
                // Reposition to start of table of authors
                var content = reviewText.Substring(startIndex + 27, endIndex - startIndex - 27);

                // Loop through all authors in database
                while (content.Contains("</tr>"))
                {
                    startIndex = content.IndexOf("href=");
                    endIndex = content.IndexOf("</tr>");

                    if (endIndex > startIndex)
                    {
                        var authorInfo = content.Substring(startIndex, endIndex - startIndex);

                        // Set content to next item in database
                        content = content.Substring(endIndex + 5);

                        XmlElement newelem = authorDatabase.CreateElement("author");
                        authorDatabase.DocumentElement.AppendChild(newelem);

                        // 0
                        // Link
                        endIndex = authorInfo.IndexOf("\">");
                        XmlElement appendedElementLink = authorDatabase.CreateElement("Link");
                        XmlText xmlTextLink = authorDatabase.CreateTextNode(Constants.WEBSITEBASE + authorInfo.Substring(6, endIndex - 6));
                        appendedElementLink.AppendChild(xmlTextLink);
                        newelem.AppendChild(appendedElementLink);
                        authorDatabase.DocumentElement.AppendChild(newelem);

                        // Reposition
                        authorInfo = authorInfo.Substring(endIndex + 2);

                        // 1
                        // Author
                        endIndex = authorInfo.IndexOf("</a>");
                        XmlElement appendedElementName = authorDatabase.CreateElement("Author");
                        XmlText xmlTextName = authorDatabase.CreateTextNode(authorInfo.Substring(0, endIndex).Trim());
                        appendedElementName.AppendChild(xmlTextName);
                        newelem.AppendChild(appendedElementName);
                        authorDatabase.DocumentElement.AppendChild(newelem);

                        // Reposition
                        startIndex = authorInfo.IndexOf("<td>");
                        authorInfo = authorInfo.Substring(startIndex + 4);

                        // 2
                        // Country
                        endIndex = authorInfo.IndexOf("</td>");
                        XmlElement appendedElementCountry = authorDatabase.CreateElement("Country");
                        XmlText xmlTextCountry = authorDatabase.CreateTextNode(authorInfo.Substring(0, endIndex).Trim());
                        appendedElementCountry.AppendChild(xmlTextCountry);
                        newelem.AppendChild(appendedElementCountry);
                        authorDatabase.DocumentElement.AppendChild(newelem);
                    }
                    else
                        // Reached end of usefull data
                        content = "";
                }
            }

            // Check for more (recursively)
            if (reviewText.Contains("pods-pagination-next"))
            {
                reviewText = reviewText.Substring(reviewText.IndexOf("pods-pagination-last"));
                reviewText = reviewText.Substring(reviewText.IndexOf("?pg="));
                endIndex = reviewText.IndexOf("\"");
                XmlDocument additionalAuthors = await FetchAuthorsInfoAsync(Constants.AUTHORFEED + reviewText.Substring(0, endIndex));

                // Append found items to the list
                XmlElement root = additionalAuthors.DocumentElement;
                XmlNodeList nodes = root.SelectNodes("author");
                foreach (var item in nodes)
                {
                    XmlElement newelem = authorDatabase.CreateElement("author");
                    authorDatabase.DocumentElement.AppendChild(newelem);

                    // 0
                    // Link
                    XmlElement appendedElementLink = authorDatabase.CreateElement("Link");
                    XmlText xmlTextLink = authorDatabase.CreateTextNode(item.ChildNodes[0].InnerText);
                    appendedElementLink.AppendChild(xmlTextLink);
                    newelem.AppendChild(appendedElementLink);
                    authorDatabase.DocumentElement.AppendChild(newelem);

                    // 1
                    // Author
                    XmlElement appendedElementName = authorDatabase.CreateElement("Author");
                    XmlText xmlTextName = authorDatabase.CreateTextNode(item.ChildNodes[1].InnerText);
                    appendedElementName.AppendChild(xmlTextName);
                    newelem.AppendChild(appendedElementName);
                    authorDatabase.DocumentElement.AppendChild(newelem);

                    // 2
                    // Country
                    XmlElement appendedElementCountry = authorDatabase.CreateElement("Country");
                    XmlText xmlTextCountry = authorDatabase.CreateTextNode(item.ChildNodes[2].InnerText);
                    appendedElementCountry.AppendChild(xmlTextCountry);
                    newelem.AppendChild(appendedElementCountry);
                    authorDatabase.DocumentElement.AppendChild(newelem);
                }
            }
            return authorDatabase;
        }
        #endregion

        #region FetchAuthorInfoFromSiteAsync
        public static async Task FetchAuthorInfoFromSiteAsync(FWDataItem item, bool updateAll = false)
        {
            try
            {
                var client = new HttpClient();
                client.MaxResponseContentBufferSize = Constants.MAX_RESPONSE_BUFFERSIZE;
                var response = await client.GetAsync(new Uri(item.Link));

                var stream = await response.Content.ReadAsStreamAsync();
                StreamReader streamReader = new StreamReader(stream);
                string authorPageText = streamReader.ReadToEnd();

                int startIndex = authorPageText.IndexOf("artikelvak");
                int endIndex = authorPageText.IndexOf("disqus_thread");
                if ((startIndex > 0) && (startIndex < endIndex))
                {
                    var content = authorPageText.Substring(startIndex, endIndex - startIndex);

                    // Determine Website
                    startIndex = content.IndexOf("Website:</strong>");
                    if (startIndex > 0)
                    {
                        startIndex = content.IndexOf("http", startIndex);

                        endIndex = content.IndexOf(">Klik hier", startIndex) - 1;
                        if ((item.Website == "") || updateAll)
                            if ((startIndex > 0) && (startIndex < endIndex))
                            {
                                item.Website = content.Substring(startIndex, endIndex - startIndex);
                                item.Content = "";
                            }
                    }

                    // Determine Content
                    startIndex = content.IndexOf("<p>");
                    endIndex = content.LastIndexOf("</p>");
                    if ((item.Content.Length == 0) || updateAll)
                        if ((startIndex > 0) && (startIndex < endIndex))
                            item.Content = Utility.CleanupNewLines(Utility.CleanupHTML(content.Substring(startIndex, endIndex - startIndex)));

                    // Set default image
                    if (item.Image == null)
                        item.SetImage(_baseUri + Constants.AUTHORFEED_UNKNOWN_IMAGE);

                    // Cleanup internal urls
                    content = content.Replace("<a href=\"\"></a>", "").Replace("<a href=\"../boeken/\"></a>", "");

                    // Reposition 
                    if ((item.Books == "") || updateAll)
                    {
                        if (updateAll)
                            item.Books = "";

                        startIndex = content.IndexOf("Boeken in onze databank");
                        if (startIndex > 0)
                        {
                            bool firstrecord = true;
                            content = content.Substring(startIndex);
                            startIndex = content.IndexOf("href=");
                            while (startIndex > 0)
                            {
                                endIndex = content.IndexOf("</a>");
                                string otherBookInfo = content.Substring(startIndex + 6, endIndex - startIndex - 6);
                                content = content.Substring(endIndex + 4);

                                string link = otherBookInfo.Substring(0, otherBookInfo.IndexOf(">") - 1).Replace("../", Constants.WEBSITEBASE + "/");
                                string titel = Utility.CleanupHTML(otherBookInfo.Substring(otherBookInfo.IndexOf(">") + 1));

                                string uniqueId = "";
                                if ((otherBookInfo.Contains("post_type=recensies&#038;")) || (otherBookInfo.StartsWith(Constants.WEBSITEBASE)))
                                    if (otherBookInfo.StartsWith(Constants.WEBSITEBASE))
                                        uniqueId = GenerateUniqueIdForReview(link);
                                    else
                                        uniqueId = "recensies/" + titel.ToLower().Replace(",", "")
                                                                                 .Replace("ï", "i")
                                                                                 .Replace("ë", "e")
                                                                                 .Replace("  ", " ")
                                                                                 .Replace(" - ", "-")
                                                                                 .Replace(":", "")
                                                                                 .Replace(" ", "-") + "/";
                                else
                                    uniqueId = otherBookInfo.Substring(0, otherBookInfo.IndexOf(">") - 1).Replace("../boeken/", Constants.BOOKFEED_BD_CODE + "-");

                                string imagePath = await getBookImageFromSite(link);

                                if (firstrecord)
                                {
                                    // Set image of book that will be linked to the author
                                    if (imagePath.Length > 0)
                                    {
                                        item.SetImage(imagePath);
                                        firstrecord = false;
                                    }
                                }
                                item.Books = item.Books + uniqueId + "|" + imagePath + "|" + titel + "|";
                                startIndex = content.IndexOf("href=");
                            }
                        }
                    }
                }
            }
            catch
            {

            }
        }

        #region GenerateUniqueIdForReview
        private static string GenerateUniqueIdForReview(string link)
        {
            return link.Substring(link.IndexOf(".nl/") + 4, link.Length - link.IndexOf(".nl/") - 4);
        }
        #endregion

        #endregion

        #region getBookImageFromSite
        public static async Task<string> getBookImageFromSite(string link)
        {
            var client = new HttpClient();
            client.MaxResponseContentBufferSize = Constants.MAX_RESPONSE_BUFFERSIZE;

            // Correct strange urls
            if (link.Contains("post_type=recensies&#038;"))
                link = link.Replace("post_type=recensies&#038;", "");

            var response = await client.GetAsync(new Uri(link));

            var stream = await response.Content.ReadAsStreamAsync();
            StreamReader streamReader = new StreamReader(stream);
            string bookPageText = streamReader.ReadToEnd();

            int startIndex = bookPageText.IndexOf("/wp-content/gallery/covers");
            if (startIndex > 0)
            {
                bookPageText = bookPageText.Substring(startIndex);
                int endIndex = bookPageText.IndexOf("jpg");
                if (endIndex > 0)
                    return Constants.WEBSITEBASE + bookPageText.Substring(0, endIndex + 3);
            }
            return "";
        }
        #endregion

        #region ReadAuthorsFromDisk
        public static void ReadAuthorsFromDisk(bool offlineMode)
        {
            XmlElement root = _FWAuthorDatabase.DocumentElement;
            XmlNodeList nodes = root.SelectNodes("item");
            foreach (var item in nodes)
            {
                FWDataItem FWItem = new FWDataItem();

                FWItem.Added = Convert.ToDateTime(item.ChildNodes[0].InnerText);
                FWItem.Age = item.ChildNodes[1].InnerText;
                FWItem.Author = item.ChildNodes[2].InnerText;
                FWItem.AuthorLink = item.ChildNodes[3].InnerText;
                FWItem.Content = item.ChildNodes[4].InnerText;
                FWItem.Description = item.ChildNodes[5].InnerText;
                FWItem.Edition = item.ChildNodes[6].InnerText;
                FWItem.Group = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(item.ChildNodes[7].InnerText));
                if (offlineMode)
                    FWItem.SetImage(FWItem.Group.ImageLink);
                else
                    FWItem.SetImage(item.ChildNodes[8].InnerText);
                FWItem.ISBN = item.ChildNodes[9].InnerText;
                FWItem.Link = item.ChildNodes[10].InnerText;
                FWItem.Price = item.ChildNodes[11].InnerText;
                FWItem.PublishDate = item.ChildNodes[12].InnerText;
                FWItem.Publisher = item.ChildNodes[13].InnerText;
                FWItem.Reviewer = item.ChildNodes[14].InnerText;
                FWItem.SetStars(item.ChildNodes[15].InnerText);
                FWItem.SubGenre = item.ChildNodes[16].InnerText;
                FWItem.Title = Utility.CleanupText(Utility.ReplaceSpecialCodes(item.ChildNodes[17].InnerText));
                FWItem.TitleOriginal = Utility.CleanupText(Utility.ReplaceSpecialCodes(item.ChildNodes[18].InnerText));
                FWItem.UniqueId = item.ChildNodes[19].InnerText;
                FWItem.Quote = item.ChildNodes[20].InnerText;
                FWItem.Translator = item.ChildNodes[21].InnerText;
                FWItem.Website = item.ChildNodes[22].InnerText;
                FWItem.Country = item.ChildNodes[23].InnerText;
                FWItem.Books = item.ChildNodes[24].InnerText;

                // Show Recent image if (and only if) the item was added more recent than two weeks ago
                FWItem.ShowRecent = FWItem.Added.AddDays(Constants.NR_RECENT_DAYS) > DateTime.Now;

                // Show Recent image if (and only if) the item was added within the last day
                FWItem.ShowNew = FWItem.Added.AddDays(Constants.NR_NEW_DAYS) > DateTime.Now;

                if (FWItem.Group.Items.FirstOrDefault(m => m.UniqueId.Equals(FWItem.UniqueId)) == null)
                {
                    // Item does not exist yet
                    // All fields have been processed
                    // Select the group and add this item to the items in this group
                    _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(FWItem.Group.UniqueId)).Items.Add(FWItem);
                }
            }

            _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.AUTHORFEED_CODE)).Count = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.AUTHORFEED_CODE)).Items.Count();
        }
        #endregion

        #endregion

        #region Handle Short Stories

        #region ProcessShortStoriesAsync
        // ProcessShortStoriesAsync
        private static async Task<bool> ProcessShortStoriesAsync(string feedName, string groupId)
        {
            bool newStoriesOnWebsite = false;

            // This function is used to initially read all data from the website
            XmlDocument onlineShortStories = await FetchShortStoriesAsync(feedName);

            XmlElement root = onlineShortStories.DocumentElement;
            XmlNodeList nodes = root.SelectNodes("story");
            foreach (var item in nodes)
            {
                FWDataItem FWItem = new FWDataItem();

                FWItem.Link = item.ChildNodes[0].InnerText;
                FWItem.UniqueId = Constants.SHORTSTORYFEED_CODE + "-" + item.ChildNodes[0].InnerText.Substring(item.ChildNodes[0].InnerText.IndexOf(".nl/") + 4);
                FWItem.Title = Utility.CleanupText(Utility.ReplaceSpecialCodes(item.ChildNodes[1].InnerText));
                FWItem.SetImage(item.ChildNodes[2].InnerText);
                FWItem.Author = item.ChildNodes[3].InnerText;
                FWItem.SubGenre = item.ChildNodes[4].InnerText;

                // Determine Group
                FWItem.Group = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(groupId));

                // Search on UniqueId
                var nodeList = _FWFullReviews.GetElementsByTagName("UniqueId");
                XmlElement node = null;

                if (nodeList.Count > 0)
                    // Find the node with this id from the review file
                    node = FindNode(nodeList, FWItem.UniqueId);

                if (node != null)
                {
                    FWItem.Added = Convert.ToDateTime(node.ParentNode.ChildNodes[0].InnerText);
                    FWItem.Age = node.ParentNode.ChildNodes[1].InnerText;
                    FWItem.Author = node.ParentNode.ChildNodes[2].InnerText;
                    FWItem.AuthorLink = node.ParentNode.ChildNodes[3].InnerText;
                    FWItem.Content = node.ParentNode.ChildNodes[4].InnerText;
                    FWItem.Description = node.ParentNode.ChildNodes[5].InnerText;
                    FWItem.Edition = node.ParentNode.ChildNodes[6].InnerText;
                    FWItem.SetImage(node.ParentNode.ChildNodes[8].InnerText);
                    FWItem.ISBN = node.ParentNode.ChildNodes[9].InnerText;
                    FWItem.Price = node.ParentNode.ChildNodes[11].InnerText;
                    FWItem.PublishDate = node.ParentNode.ChildNodes[12].InnerText;
                    FWItem.Publisher = node.ParentNode.ChildNodes[13].InnerText;
                    FWItem.Reviewer = node.ParentNode.ChildNodes[14].InnerText;
                    FWItem.SetStars(node.ParentNode.ChildNodes[15].InnerText);
                    FWItem.SubGenre = node.ParentNode.ChildNodes[16].InnerText;
                    FWItem.TitleOriginal = Utility.CleanupText(Utility.ReplaceSpecialCodes(node.ParentNode.ChildNodes[18].InnerText));
                }
                else
                {
                    // Go to website and fetch full book content 
                    await FetchShortStoryInfoFromSiteAsync(FWItem);

                    // Add new record to search suggestion list
                    ProcessSuggestions(FWItem);

                    newStoriesOnWebsite = true;
                }

                bool isInCollection = false;
                foreach (var existingItem in _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(FWItem.Group.UniqueId)).Items)
                {
                    if (existingItem.UniqueId.Equals(FWItem.UniqueId))
                    {
                        isInCollection = true;
                        break;
                    }
                }

                if (!isInCollection)
                {
                    // All fields have been processed
                    // Select the group and add this item to the items in this group
                    _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(FWItem.Group.UniqueId)).Items.Add(FWItem);

                    // Determine the number of items in this group
                    _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(FWItem.Group.UniqueId)).Count = _FWDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(FWItem.Group.UniqueId)).Items.Count();
                }
            }

            return newStoriesOnWebsite;
        }
        #endregion

        #region FetchShortStoriesAsync
        public static async Task<XmlDocument> FetchShortStoriesAsync(string feedName)
        {
            XmlDocument onlineShortStories = new XmlDocument();
            onlineShortStories.LoadXml(Constants.XML_BASE_FILE);

            var client = new HttpClient();
            client.MaxResponseContentBufferSize = Constants.MAX_RESPONSE_BUFFERSIZE;
            var response = await client.GetAsync(new Uri(feedName));

            var stream = await response.Content.ReadAsStreamAsync();
            StreamReader streamReader = new StreamReader(stream);
            string storyList = streamReader.ReadToEnd();

            int startIndex = storyList.IndexOf("dotted");
            int endIndex = storyList.IndexOf("</tr></table>") + 5;
            if ((startIndex > 0) && (startIndex < endIndex))
            {
                // Reposition to start of table of books
                var content = storyList.Substring(startIndex + 18, endIndex - startIndex - 18);

                // Loop through all books in database
                while (content.Contains("<tr><td><a class="))
                {
                    // Reposition
                    content = content.Substring(content.IndexOf("<tr><td><a class="));

                    startIndex = content.IndexOf("href=");
                    endIndex = content.IndexOf("</tr>");

                    if (endIndex > startIndex)
                    {
                        var storyInfo = content.Substring(startIndex, endIndex - startIndex);

                        // Set content to next item in database
                        content = content.Substring(endIndex + 5);

                        XmlElement newelem = onlineShortStories.CreateElement("story");
                        onlineShortStories.DocumentElement.AppendChild(newelem);

                        // 0
                        // Link
                        endIndex = storyInfo.IndexOf("\">");
                        XmlElement appendedElementLink = onlineShortStories.CreateElement("Link");
                        XmlText xmlTextLink = onlineShortStories.CreateTextNode(storyInfo.Substring(6, endIndex - 6));
                        appendedElementLink.AppendChild(xmlTextLink);
                        newelem.AppendChild(appendedElementLink);
                        onlineShortStories.DocumentElement.AppendChild(newelem);

                        // Reposition
                        storyInfo = storyInfo.Substring(endIndex + 2);

                        // 1
                        // Titel
                        endIndex = storyInfo.IndexOf("<span>");
                        XmlElement appendedElementTitel = onlineShortStories.CreateElement("Titel");
                        XmlText xmlTextTitel = onlineShortStories.CreateTextNode(storyInfo.Substring(0, endIndex).Trim());
                        appendedElementTitel.AppendChild(xmlTextTitel);
                        newelem.AppendChild(appendedElementTitel);
                        onlineShortStories.DocumentElement.AppendChild(newelem);

                        // Reposition
                        startIndex = storyInfo.IndexOf("http:");
                        storyInfo = storyInfo.Substring(startIndex);

                        // 2
                        // Image
                        endIndex = storyInfo.IndexOf(".jpg");
                        XmlElement appendedElementImage = onlineShortStories.CreateElement("Image");
                        XmlText xmlTextImage = onlineShortStories.CreateTextNode(storyInfo.Substring(0, endIndex + 4).Trim());
                        appendedElementImage.AppendChild(xmlTextImage);
                        newelem.AppendChild(appendedElementImage);
                        onlineShortStories.DocumentElement.AppendChild(newelem);

                        // Reposition
                        startIndex = storyInfo.IndexOf("<td>");
                        storyInfo = storyInfo.Substring(startIndex + 4);

                        // 3
                        // Author
                        endIndex = storyInfo.IndexOf("</td>");
                        XmlElement appendedElementAuthor = onlineShortStories.CreateElement("Author");
                        XmlText xmlTextAuthor = onlineShortStories.CreateTextNode(storyInfo.Substring(0, endIndex).Trim());
                        appendedElementAuthor.AppendChild(xmlTextAuthor);
                        newelem.AppendChild(appendedElementAuthor);
                        onlineShortStories.DocumentElement.AppendChild(newelem);

                        // Reposition
                        startIndex = storyInfo.LastIndexOf("<td>");
                        storyInfo = storyInfo.Substring(startIndex + 4);

                        // 4
                        // SubGenre
                        endIndex = storyInfo.IndexOf("<br />");
                        XmlElement appendedElementSubGenre = onlineShortStories.CreateElement("SubGenre");
                        XmlText xmlTextSubGenre = onlineShortStories.CreateTextNode(storyInfo.Substring(0, endIndex).Trim());
                        appendedElementSubGenre.AppendChild(xmlTextSubGenre);
                        newelem.AppendChild(appendedElementSubGenre);
                        onlineShortStories.DocumentElement.AppendChild(newelem);
                    }
                    else
                        // Reached end of usefull data
                        content = "";
                }
            }

            // Check for more (recursively)
            if (storyList.Contains("pods-pagination-next"))
            {
                storyList = storyList.Substring(storyList.IndexOf("pods-pagination-last"));
                storyList = storyList.Substring(storyList.IndexOf("?pg="));
                endIndex = storyList.IndexOf("\"");
                XmlDocument additionalReviews = await FetchShortStoriesAsync(Constants.SHORTSTORYFEED + storyList.Substring(0, endIndex));

                // Append found items to the list
                XmlElement root = additionalReviews.DocumentElement;
                XmlNodeList nodes = root.SelectNodes("story");
                foreach (var item in nodes)
                {
                    XmlElement newelem = onlineShortStories.CreateElement("story");
                    onlineShortStories.DocumentElement.AppendChild(newelem);

                    // 0
                    // Link
                    XmlElement appendedElementLink = onlineShortStories.CreateElement("Link");
                    XmlText xmlTextLink = onlineShortStories.CreateTextNode(item.ChildNodes[0].InnerText);
                    appendedElementLink.AppendChild(xmlTextLink);
                    newelem.AppendChild(appendedElementLink);
                    onlineShortStories.DocumentElement.AppendChild(newelem);

                    // 1
                    // Titel
                    XmlElement appendedElementTitel = onlineShortStories.CreateElement("Titel");
                    XmlText xmlTextTitel = onlineShortStories.CreateTextNode(item.ChildNodes[1].InnerText);
                    appendedElementTitel.AppendChild(xmlTextTitel);
                    newelem.AppendChild(appendedElementTitel);
                    onlineShortStories.DocumentElement.AppendChild(newelem);

                    // 2
                    // Image
                    XmlElement appendedElementImage = onlineShortStories.CreateElement("Image");
                    XmlText xmlTextImage = onlineShortStories.CreateTextNode(item.ChildNodes[2].InnerText);
                    appendedElementImage.AppendChild(xmlTextImage);
                    newelem.AppendChild(appendedElementImage);
                    onlineShortStories.DocumentElement.AppendChild(newelem);

                    // 3
                    // Author
                    XmlElement appendedElementAuthor = onlineShortStories.CreateElement("Author");
                    XmlText xmlTextAuthor = onlineShortStories.CreateTextNode(item.ChildNodes[3].InnerText);
                    appendedElementAuthor.AppendChild(xmlTextAuthor);
                    newelem.AppendChild(appendedElementAuthor);
                    onlineShortStories.DocumentElement.AppendChild(newelem);

                    // 4
                    // SubGenre
                    XmlElement appendedElementSubGenre = onlineShortStories.CreateElement("SubGenre");
                    XmlText xmlTextSubGenre = onlineShortStories.CreateTextNode(item.ChildNodes[4].InnerText);
                    appendedElementSubGenre.AppendChild(xmlTextSubGenre);
                    newelem.AppendChild(appendedElementSubGenre);
                    onlineShortStories.DocumentElement.AppendChild(newelem);
                }
            }
            return onlineShortStories;
        }
        #endregion

        #region FetchShortStoryInfoFromSiteAsync
        public static async Task FetchShortStoryInfoFromSiteAsync(FWDataItem item)
        {
            var client = new HttpClient();
            client.MaxResponseContentBufferSize = Constants.MAX_RESPONSE_BUFFERSIZE;
            var response = await client.GetAsync(new Uri(item.Link));

            var stream = await response.Content.ReadAsStreamAsync();
            StreamReader streamReader = new StreamReader(stream);
            string storyText = streamReader.ReadToEnd();

            int startIndex = storyText.IndexOf("Auteur:");
            int endIndex = storyText.IndexOf("</iframe>");
            if ((startIndex > 0) && (startIndex < endIndex))
            {
                var content = storyText.Substring(startIndex, endIndex + 9 - startIndex);

                // Determine AuthorLink
                startIndex = content.IndexOf("<a href=");
                endIndex = content.IndexOf("\">");
                if (endIndex > startIndex)
                    item.AuthorLink = content.Substring(startIndex + 9, endIndex - startIndex - 9);

                // Determine Content
                startIndex = content.IndexOf("<p>");
                item.Content = content.Substring(startIndex).Replace("</div>", "").Replace("<hr class=\"dotted\">", "").Replace("\"//", "\"http://");

                // Determine Description
                item.Description = Utility.CleanupNewLines(Utility.CleanupHTML(item.Content));
            }
        }
        #endregion

        #endregion
    }
}